Merge "[Partial Screensharing] Add enterprise policies resolver" into tm-qpr-dev
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 2e3b5d2..80cea55 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1187,6 +1187,79 @@
@Overridable
public static final long OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS = 263259275L;
+ // Compat framework that per-app overrides rely on only supports booleans. That's why we have
+ // multiple OVERRIDE_*_ORIENTATION_* change ids below instead of just one override with
+ // the integer value.
+
+ /**
+ * Enables {@link #SCREEN_ORIENTATION_PORTRAIT}. Unless OVERRIDE_ANY_ORIENTATION
+ * is enabled, this override is used only when no other fixed orientation was specified by the
+ * activity.
+ * @hide
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT = 265452344L;
+
+ /**
+ * Enables {@link #SCREEN_ORIENTATION_NOSENSOR}. Unless OVERRIDE_ANY_ORIENTATION
+ * is enabled, this override is used only when no other fixed orientation was specified by the
+ * activity.
+ * @hide
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR = 265451093L;
+
+ /**
+ * Enables {@link #SCREEN_ORIENTATION_REVERSE_LANDSCAPE}. Unless OVERRIDE_ANY_ORIENTATION
+ * is enabled, this override is used only when activity specify landscape orientation.
+ * This can help apps that assume that landscape display orientation corresponds to {@link
+ * android.view.Surface#ROTATION_90}, while on some devices it can be {@link
+ * android.view.Surface#ROTATION_270}.
+ * @hide
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE = 266124927L;
+
+ /**
+ * When enabled, allows OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE,
+ * OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR and OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
+ * to override any orientation requested by the activity.
+ * @hide
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long OVERRIDE_ANY_ORIENTATION = 265464455L;
+
+ /**
+ * This override fixes display orientation to landscape natural orientation when a task is
+ * fullscreen. While display rotation is fixed to landscape, the orientation requested by the
+ * activity will be still respected by bounds resolution logic. For instance, if an activity
+ * requests portrait orientation and this override is set, then activity will appear in the
+ * letterbox mode for fixed orientation with the display rotated to the lanscape natural
+ * orientation.
+ *
+ * <p>This override is applicable only when natural orientation of the device is
+ * landscape and display ignores orientation requestes.
+ *
+ * <p>Main use case for this override are camera-using activities that are portrait-only and
+ * assume alignment with natural device orientation. Such activities can automatically be
+ * rotated with com.android.server.wm.DisplayRotationCompatPolicy but not all of them can
+ * handle dynamic rotation and thus can benefit from this override.
+ *
+ * @hide
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION = 255940284L;
+
/**
* Compares activity window layout min width/height with require space for multi window to
* determine if it can be put into multi window mode.
@@ -1405,8 +1478,19 @@
* @hide
*/
public boolean isFixedOrientation() {
- return isFixedOrientationLandscape() || isFixedOrientationPortrait()
- || screenOrientation == SCREEN_ORIENTATION_LOCKED;
+ return isFixedOrientation(screenOrientation);
+ }
+
+ /**
+ * Returns true if the passed activity's orientation is fixed.
+ * @hide
+ */
+ public static boolean isFixedOrientation(@ScreenOrientation int orientation) {
+ return orientation == SCREEN_ORIENTATION_LOCKED
+ // Orientation is fixed to natural display orientation
+ || orientation == SCREEN_ORIENTATION_NOSENSOR
+ || isFixedOrientationLandscape(orientation)
+ || isFixedOrientationPortrait(orientation);
}
/**
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index df1c0d7..e5243ee 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -878,8 +878,8 @@
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code VIDEO_CALL}</td> <td colspan="3" id="rb"></td> <td>Preview with video call</td> </tr>
* <tr> <td>{@code YUV / PRIV}</td><td id="rb">{@code s1440p}</td><td id="rb">{@code PREVIEW_VIDEO_STILL}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>Multi-purpose stream with JPEG or YUV still capture</td> </tr>
* <tr> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td colspan="3" id="rb"></td> <td>YUV and JPEG concurrent still image capture (for testing)</td> </tr>
- * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, video record and JPEG or YUV video snapshot</td> </tr>
- * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, in-application image processing, and JPEG or YUV still image capture</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV / PRIV}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code VIDEO_RECORD}</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, video record and JPEG video snapshot</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td><td id="rb">{@code STILL_CAPTURE}</td> <td>Preview, in-application image processing, and JPEG still image capture</td> </tr>
* </table><br>
* </p>
*
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index e5b9cdb..754472f 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -1223,14 +1223,6 @@
new StreamCombinationTemplate(new StreamTemplate [] {
new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
STREAM_USE_CASE_PREVIEW),
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
- STREAM_USE_CASE_RECORD),
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
- STREAM_USE_CASE_STILL_CAPTURE)},
- "Preview, video record and YUV video snapshot"),
- new StreamCombinationTemplate(new StreamTemplate [] {
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
- STREAM_USE_CASE_PREVIEW),
new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
STREAM_USE_CASE_RECORD),
new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD,
@@ -1239,27 +1231,11 @@
new StreamCombinationTemplate(new StreamTemplate [] {
new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
STREAM_USE_CASE_PREVIEW),
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
- STREAM_USE_CASE_RECORD),
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
- STREAM_USE_CASE_STILL_CAPTURE)},
- "Preview, in-application video processing and YUV video snapshot"),
- new StreamCombinationTemplate(new StreamTemplate [] {
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
- STREAM_USE_CASE_PREVIEW),
new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
STREAM_USE_CASE_PREVIEW),
new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
STREAM_USE_CASE_STILL_CAPTURE)},
"Preview, in-application image processing, and JPEG still image capture"),
- new StreamCombinationTemplate(new StreamTemplate [] {
- new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
- STREAM_USE_CASE_PREVIEW),
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
- STREAM_USE_CASE_PREVIEW),
- new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
- STREAM_USE_CASE_STILL_CAPTURE)},
- "Preview, in-application image processing, and YUV still image capture"),
};
private static StreamCombinationTemplate sPreviewStabilizedStreamCombinations[] = {
diff --git a/core/java/android/service/quickaccesswallet/WalletCard.java b/core/java/android/service/quickaccesswallet/WalletCard.java
index b09d2e9..7aacb9b 100644
--- a/core/java/android/service/quickaccesswallet/WalletCard.java
+++ b/core/java/android/service/quickaccesswallet/WalletCard.java
@@ -16,6 +16,7 @@
package android.service.quickaccesswallet;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -24,28 +25,73 @@
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+
/**
* A {@link WalletCard} can represent anything that a user might carry in their wallet -- a credit
* card, library card, transit pass, etc. Cards are identified by a String identifier and contain a
- * card image, card image content description, and a {@link PendingIntent} to be used if the user
- * clicks on the card. Cards may be displayed with an icon and label, though these are optional.
+ * card type, card image, card image content description, and a {@link PendingIntent} to be used if
+ * the user clicks on the card. Cards may be displayed with an icon and label, though these are
+ * optional. Valuable cards will also have a second image that will be displayed when the card is
+ * tapped.
*/
+
public final class WalletCard implements Parcelable {
+ /**
+ * Unknown cards refer to cards whose types are unspecified.
+ * @hide
+ */
+ public static final int CARD_TYPE_UNKNOWN = 0;
+
+ /**
+ * Payment cards refer to credit cards, debit cards or any other cards in the wallet used to
+ * make cash-equivalent payments.
+ * @hide
+ */
+ public static final int CARD_TYPE_PAYMENT = 1;
+
+ /**
+ * Valuable cards refer to any cards that are not used for cash-equivalent payment.
+ * This includes event tickets, flights, offers, loyalty cards, gift cards and transit tickets.
+ * @hide
+ */
+ public static final int CARD_TYPE_VALUABLE = 2;
+
private final String mCardId;
+ private final int mCardType;
private final Icon mCardImage;
private final CharSequence mContentDescription;
private final PendingIntent mPendingIntent;
private final Icon mCardIcon;
private final CharSequence mCardLabel;
+ private final Icon mValuableCardSecondaryImage;
private WalletCard(Builder builder) {
this.mCardId = builder.mCardId;
+ this.mCardType = builder.mCardType;
this.mCardImage = builder.mCardImage;
this.mContentDescription = builder.mContentDescription;
this.mPendingIntent = builder.mPendingIntent;
this.mCardIcon = builder.mCardIcon;
this.mCardLabel = builder.mCardLabel;
+ this.mValuableCardSecondaryImage = builder.mValuableCardSecondaryImage;
+ }
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"CARD_TYPE_"}, value = {
+ CARD_TYPE_UNKNOWN,
+ CARD_TYPE_PAYMENT,
+ CARD_TYPE_VALUABLE
+ })
+ public @interface CardType {
}
@Override
@@ -56,29 +102,44 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mCardId);
+ dest.writeInt(mCardType);
mCardImage.writeToParcel(dest, flags);
TextUtils.writeToParcel(mContentDescription, dest, flags);
PendingIntent.writePendingIntentOrNullToParcel(mPendingIntent, dest);
- if (mCardIcon == null) {
+ writeIconIfNonNull(mCardIcon, dest, flags);
+ TextUtils.writeToParcel(mCardLabel, dest, flags);
+ writeIconIfNonNull(mValuableCardSecondaryImage, dest, flags);
+
+ }
+
+ /** Utility function called by writeToParcel
+ */
+ private void writeIconIfNonNull(Icon icon, Parcel dest, int flags) {
+ if (icon == null) {
dest.writeByte((byte) 0);
} else {
dest.writeByte((byte) 1);
- mCardIcon.writeToParcel(dest, flags);
+ icon.writeToParcel(dest, flags);
}
- TextUtils.writeToParcel(mCardLabel, dest, flags);
}
private static WalletCard readFromParcel(Parcel source) {
String cardId = source.readString();
+ int cardType = source.readInt();
Icon cardImage = Icon.CREATOR.createFromParcel(source);
CharSequence contentDesc = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
PendingIntent pendingIntent = PendingIntent.readPendingIntentOrNullFromParcel(source);
Icon cardIcon = source.readByte() == 0 ? null : Icon.CREATOR.createFromParcel(source);
CharSequence cardLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- return new Builder(cardId, cardImage, contentDesc, pendingIntent)
+ Icon valuableCardSecondaryImage = source.readByte() == 0 ? null :
+ Icon.CREATOR.createFromParcel(source);
+ Builder builder = new Builder(cardId, cardType, cardImage, contentDesc, pendingIntent)
.setCardIcon(cardIcon)
- .setCardLabel(cardLabel)
- .build();
+ .setCardLabel(cardLabel);
+
+ return cardType == CARD_TYPE_VALUABLE
+ ? builder.setValuableCardSecondaryImage(valuableCardSecondaryImage).build() :
+ builder.build();
}
@NonNull
@@ -104,6 +165,16 @@
}
/**
+ * Returns the card type.
+ * @hide
+ */
+ @NonNull
+ @CardType
+ public int getCardType() {
+ return mCardType;
+ }
+
+ /**
* The visual representation of the card. If the card image Icon is a bitmap, it should have a
* width of {@link GetWalletCardsRequest#getCardWidthPx()} and a height of {@link
* GetWalletCardsRequest#getCardHeightPx()}.
@@ -158,23 +229,37 @@
}
/**
- * Builder for {@link WalletCard} objects. You must to provide cardId, cardImage,
+ * Visual representation of the card when it is tapped. Includes a barcode to scan the card in
+ * addition to the information in the primary image.
+ * @hide
+ */
+ @Nullable
+ public Icon getValuableCardSecondaryImage() {
+ return mValuableCardSecondaryImage;
+ }
+
+ /**
+ * Builder for {@link WalletCard} objects. You must provide cardId, cardImage,
* contentDescription, and pendingIntent. If the card is opaque and should be shown with
* elevation, set hasShadow to true. cardIcon and cardLabel are optional.
*/
public static final class Builder {
private String mCardId;
+ private int mCardType;
private Icon mCardImage;
private CharSequence mContentDescription;
private PendingIntent mPendingIntent;
private Icon mCardIcon;
private CharSequence mCardLabel;
+ private Icon mValuableCardSecondaryImage;
/**
* @param cardId The card id must be non-null and unique within the list of
* cards returned. <b>Note:
* </b> this card ID should <b>not</b> contain PII (Personally
* Identifiable Information, such as username or email address).
+ * @param cardType Integer representing the card type. The card type must be
+ * non-null. If not provided, it defaults to unknown.
* @param cardImage The visual representation of the card. If the card image Icon
* is a bitmap, it should have a width of {@link
* GetWalletCardsRequest#getCardWidthPx()} and a height of {@link
@@ -193,15 +278,30 @@
* request device unlock before sending the pending intent. It is
* recommended that the pending intent be immutable (use {@link
* PendingIntent#FLAG_IMMUTABLE}).
+ * @hide
+ */
+ public Builder(@NonNull String cardId,
+ @NonNull @CardType int cardType,
+ @NonNull Icon cardImage,
+ @NonNull CharSequence contentDescription,
+ @NonNull PendingIntent pendingIntent
+ ) {
+ mCardId = cardId;
+ mCardType = cardType;
+ mCardImage = cardImage;
+ mContentDescription = contentDescription;
+ mPendingIntent = pendingIntent;
+ }
+
+ /**
+ * Called when a card type is not provided.
*/
public Builder(@NonNull String cardId,
@NonNull Icon cardImage,
@NonNull CharSequence contentDescription,
@NonNull PendingIntent pendingIntent) {
- mCardId = cardId;
- mCardImage = cardImage;
- mContentDescription = contentDescription;
- mPendingIntent = pendingIntent;
+ this(cardId, WalletCard.CARD_TYPE_UNKNOWN, cardImage, contentDescription,
+ pendingIntent);
}
/**
@@ -236,6 +336,19 @@
}
/**
+ * Visual representation of the card when it is tapped. Includes a barcode to scan the card
+ * in addition to the information in the primary image.
+ * @hide
+ */
+ @NonNull
+ public Builder setValuableCardSecondaryImage(@Nullable Icon valuableCardSecondaryImage) {
+ Preconditions.checkState(mCardType == CARD_TYPE_VALUABLE,
+ "This field can only be set on valuable cards");
+ mValuableCardSecondaryImage = valuableCardSecondaryImage;
+ return this;
+ }
+
+ /**
* Builds a new {@link WalletCard} instance.
*
* @return A built response.
diff --git a/core/java/android/util/SparseSetArray.java b/core/java/android/util/SparseSetArray.java
index b7873b7..61f29a4 100644
--- a/core/java/android/util/SparseSetArray.java
+++ b/core/java/android/util/SparseSetArray.java
@@ -139,4 +139,9 @@
public T valueAt(int intIndex, int valueIndex) {
return mData.valueAt(intIndex).valueAt(valueIndex);
}
+
+ /** @return The set of values for key at position {@code intIndex}. */
+ public ArraySet<T> valuesAt(int intIndex) {
+ return mData.valueAt(intIndex);
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a37c244..e3bf2d4 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -990,6 +990,77 @@
"android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
/**
+ * Activity level {@link android.content.pm.PackageManager.Property PackageManager
+ * .Property} for an app to inform the system that the activity should be excluded from the
+ * compatibility override for orientation set by the device manufacturer.
+ *
+ * <p>With this property set to {@code true} or unset, device manufacturers can override
+ * orientation for the activity using their discretion to improve display compatibility.
+ *
+ * <p>With this property set to {@code false}, device manufactured per-app override for
+ * orientation won't be applied.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * <activity>
+ * <property
+ * android:name="android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE"
+ * android:value="true|false"/>
+ * </activity>
+ * </pre>
+ *
+ * @hide
+ */
+ // TODO(b/263984287): Make this public API.
+ String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE =
+ "android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
+
+ /**
+ * Activity level {@link android.content.pm.PackageManager.Property PackageManager
+ * .Property} for an app to inform the system that the activity should be opted-out from the
+ * compatibility override that fixes display orientation to landscape natural orientation when
+ * an activity is fullscreen.
+ *
+ * <p>When this compat override is enabled and while display is fixed to the landscape natural
+ * orientation, the orientation requested by the activity will be still respected by bounds
+ * resolution logic. For instance, if an activity requests portrait orientation, then activity
+ * will appear in the letterbox mode for fixed orientation with the display rotated to the
+ * lanscape natural orientation.
+ *
+ * <p>The treatment is disabled by default but device manufacturers can enable the treatment
+ * using their discretion to improve display compatibility on the displays that have
+ * ignoreOrientationRequest display setting enabled (enables compatibility mode for fixed
+ * orientation, see <a href="https://developer.android.com/guide/practices/enhanced-letterboxing">Enhanced letterboxing</a>
+ * for more details).
+ *
+ * <p>With this property set to {@code true} or unset, the system wiil use landscape display
+ * orientation when the following conditions are met:
+ * <ul>
+ * <li>Natural orientation of the display is landscape
+ * <li>ignoreOrientationRequest display setting is enabled
+ * <li>Activity is fullscreen.
+ * <li>Device manufacturer enabled the treatment.
+ * </ul>
+ *
+ * <p>With this property set to {@code false}, device manufactured per-app override for
+ * display orientation won't be applied.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * <activity>
+ * <property
+ * android:name="android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE"
+ * android:value="true|false"/>
+ * </activity>
+ * </pre>
+ *
+ * @hide
+ */
+ // TODO(b/263984287): Make this public API.
+ String PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE =
+ "android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE";
+
+ /**
* @hide
*/
public static final String PARCEL_KEY_SHORTCUTS_ARRAY = "shortcuts_array";
diff --git a/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java b/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
index e3cc4f1..d0b5811 100644
--- a/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
+++ b/core/java/com/android/internal/app/ChooserActivityLoggerImpl.java
@@ -47,7 +47,9 @@
/* num_app_provided_app_targets = 6 */ appProvidedApp,
/* is_workprofile = 7 */ isWorkprofile,
/* previewType = 8 */ typeFromPreviewInt(previewType),
- /* intentType = 9 */ typeFromIntentString(intent));
+ /* intentType = 9 */ typeFromIntentString(intent),
+ /* num_provided_custom_actions = 10 */ 0,
+ /* reselection_action_provided = 11 */ false);
}
@Override
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 4f7f8ba..b9373be 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -567,11 +567,6 @@
public static final String VOLUME_SEPARATE_NOTIFICATION = "volume_separate_notification";
/**
- * (boolean) Whether the clipboard overlay is enabled.
- */
- public static final String CLIPBOARD_OVERLAY_ENABLED = "clipboard_overlay_enabled";
-
- /**
* (boolean) Whether widget provider info would be saved to / loaded from system persistence
* layer as opposed to individual manifests in respective apps.
*/
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index 8e4006a..e029af4 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -110,11 +110,20 @@
// All of this type/caption enabled for current profiles.
repeated android.content.ComponentNameProto enabled = 3;
-
repeated ManagedServiceInfoProto live_services = 4;
+ // Was: repeated ComponentNameProto, when snoozed services were not per-user-id.
+ reserved 5;
+
+ message SnoozedServices {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 user_id = 1;
+ repeated android.content.ComponentNameProto snoozed = 2;
+ }
+
// Snoozed for current profiles.
- repeated android.content.ComponentNameProto snoozed = 5;
+ repeated SnoozedServices snoozed = 6;
}
message RankingHelperProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6a80d1c..b10df60 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3893,7 +3893,7 @@
<p>Should only be requested by the System, should be required by
TileService declarations.-->
<permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|recents" />
<!-- Allows SystemUI to request third party controls.
<p>Should only be requested by the System and required by
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index 50e6f33..a5ff470 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -17,6 +17,7 @@
*/
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/item"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b49f8c2..ef746fa 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Bekyk tans volskerm"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Swiep van bo na onder as jy wil uitgaan."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Het dit"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Klaar"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ure se sirkelglyer"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minute se sirkelglyer"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index d5d8fe5..89039a6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"ሙሉ ገጽ በማሳየት ላይ"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ለመውጣት፣ ከላይ ወደታች ጠረግ ያድርጉ።"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ገባኝ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"ተከናውኗል"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"የሰዓታት ክብ ተንሸራታች"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"የደቂቃዎች ክብ ተንሸራታች"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index cbf18251..b04af91 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1844,6 +1844,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"جارٍ العرض بملء الشاشة"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"للخروج، مرر بسرعة من أعلى إلى أسفل."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"حسنًا"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"تم"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"شريط التمرير الدائري للساعات"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"شريط التمرير الدائري للدقائق"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e544de5..cd69314 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"স্ক্ৰীন পূৰ্ণৰূপত চাই আছে"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"বাহিৰ হ\'বলৈ ওপৰৰপৰা তললৈ ছোৱাইপ কৰক।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"বুজি পালোঁ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"সম্পন্ন কৰা হ’ল"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ঘড়ীৰ বৃত্তাকাৰ শ্লাইডাৰ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"মিনিটৰ বৃত্তাকাৰ শ্লাইডাৰ"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 9a4e5ce..5abd2b6 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Tam ekrana baxış"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Çıxmaq üçün yuxarıdan aşağı sürüşdürün."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Anladım"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Hazırdır"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Dairəvi saat slayderi"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Dairəvi dəqiqə slayderi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index c183da8..b2dbfd0 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Prikazuje se ceo ekran"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Da biste izašli, prevucite nadole odozgo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Važi"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Gotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kružni klizač za sate"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kružni klizač za minute"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2d8f21d..fa0ebc1 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Прагляд у поўнаэкранным рэжыме"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Для выхаду правядзіце зверху ўніз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Зразумела"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Гатова"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Кругавы паўзунок гадзін"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Кругавы паўзунок хвілін"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d418409..ba4466f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Изглед на цял екран"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"За изход плъзнете пръст надолу от горната част."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Разбрах"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Кръгов плъзгач за часовете"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Кръгов плъзгач за минутите"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index c8ec80f..ef51384 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"পূর্ণ স্ক্রিনে দেখা হচ্ছে"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"প্রস্থান করতে উপর থেকে নিচের দিকে সোয়াইপ করুন"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"বুঝেছি"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"সম্পন্ন হয়েছে"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"বৃত্তাকার ঘণ্টা নির্বাচকের স্লাইডার"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"বৃত্তাকার মিনিট নির্বাচকের স্লাইডার"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 46b3f6c..fd5cd64 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Prikazuje se cijeli ekran"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Da izađete, prevucite odozgo nadolje."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Razumijem"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Gotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kružni klizač za odabir sata"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kružni klizač za minute"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index f7745f0..153f430 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Mode de pantalla completa"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Per sortir, llisca cap avall des de la part superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entesos"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Fet"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control circular de les hores"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control circular dels minuts"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ea61fea..24617d0 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Zobrazení celé obrazovky"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Režim ukončíte přejetím prstem shora dolů."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Rozumím"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Hotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kruhový posuvník hodin"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kruhový posuvník minut"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ca619b3..bcc7d50 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visning i fuld skærm"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Stryg ned fra toppen for at afslutte."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK, det er forstået"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Udfør"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Cirkulær timevælger"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Cirkulær minutvælger"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 876d3a1..0df4fc6 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Vollbildmodus wird aktiviert"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Zum Beenden von oben nach unten wischen"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ok"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Fertig"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kreisförmiger Schieberegler für Stunden"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kreisförmiger Schieberegler für Minuten"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 172365f..8c354fb 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Προβολή σε πλήρη οθόνη"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Για έξοδο, σύρετε προς τα κάτω από το επάνω μέρος."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Το κατάλαβα"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Τέλος"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Κυκλικό ρυθμιστικό ωρών"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Κυκλικό ρυθμιστικό λεπτών"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index f42a577..fc37786 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Viewing full screen"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 76ca7cf..c8d6ca5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Viewing full screen"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index e627764..7bc59d7 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Viewing full screen"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 565cbd9..997929d 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Viewing full screen"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 2718d42..601c498 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Viewing full screen"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"To exit, swipe down from the top."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Got it"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Done"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Hours circular slider"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutes circular slider"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 4e5c8f7..884b767 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visualización en pantalla completa"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Para salir, desliza el dedo hacia abajo desde la parte superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendido"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Listo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control deslizante circular de horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control deslizante circular de minutos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 54e22d3..b26ee6a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Modo de pantalla completa"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Para salir, desliza el dedo de arriba abajo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendido"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Hecho"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control deslizante circular de horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control deslizante circular de minutos"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index c727137..0c95591 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Kuvamine täisekraanil"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Väljumiseks pühkige ülevalt alla."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Selge"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Valmis"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ringikujuline tunniliugur"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Ringikujuline minutiliugur"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index bba9c9c..0dffb90 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Pantaila osoko ikuspegia"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Irteteko, pasatu hatza goitik behera."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ados"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Eginda"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ordua aukeratzeko ikuspegi zirkularra"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minutuak aukeratzeko ikuspegi zirkularra"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f9fa48d..20b6745 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -575,7 +575,7 @@
<string name="permdesc_mediaLocation" msgid="597912899423578138">"به برنامه اجازه میدهد مکانها را از مجموعه رسانهتان بخواند."</string>
<string name="biometric_app_setting_name" msgid="3339209978734534457">"استفاده از زیستسنجشی"</string>
<string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استفاده از زیستسنجشی یا قفل صفحه"</string>
- <string name="biometric_dialog_default_title" msgid="55026799173208210">"تأیید کنید این شما هستید"</string>
+ <string name="biometric_dialog_default_title" msgid="55026799173208210">"تأیید کنید این شمایید"</string>
<string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"برای ادامه، از زیستسنجشی استفاده کنید"</string>
<string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"برای ادامه، از زیستسنجشی یا قفل صفحه استفاده کنید"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"سختافزار زیستسنجی دردسترس نیست"</string>
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"مشاهده در حالت تمام صفحه"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"متوجه شدم"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"تمام"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"لغزنده دایرهای ساعت"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"لغزنده دایرهای دقیقه"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c81bf00..df9cc2e 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Koko ruudun tilassa"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Sulje palkki pyyhkäisemällä alas ruudun ylälaidasta."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Selvä"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Valmis"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Tuntien ympyränmuotoinen liukusäädin"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minuuttien ympyränmuotoinen liukusäädin"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 40b265a..eb8a778 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Affichage plein écran"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Pour quitter, balayez vers le bas à partir du haut."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Terminé"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Curseur circulaire des heures"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Curseur circulaire des minutes"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c2a8460..480a7b5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Affichage en plein écran"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Pour quitter, balayez l\'écran du haut vers le bas."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"OK"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Curseur circulaire des heures"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Curseur circulaire des minutes"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 9353cf8..1e8063a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Vendo pantalla completa"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Para saír, pasa o dedo cara abaixo desde a parte superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendido"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Feito"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Control desprazable circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Control desprazable circular dos minutos"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index ad006c6..45f12d7 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"પૂર્ણ સ્ક્રીન પર જુઓ"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"બહાર નીકળવા માટે, ટોચ પરથી નીચે સ્વાઇપ કરો."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"સમજાઈ ગયું"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"થઈ ગયું"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"કલાકનું વર્તુળાકાર સ્લાઇડર"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"મિનિટનું વર્તુળાકાર સ્લાઇડર"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 2a472f8..f145a4c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"आप पूरे स्क्रीन पर देख रहे हैं"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"बाहर निकलने के लिए, ऊपर से नीचे स्वाइप करें."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ठीक है"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"हो गया"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"घंटो का चक्राकार स्लाइडर"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"मिनटों का चक्राकार स्लाइडर"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 72480a4..e126941 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Gledanje preko cijelog zaslona"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Za izlaz prijeđite prstom od vrha prema dolje."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Shvaćam"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Gotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kružni klizač sati"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kružni klizač minuta"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f9a93a8..a529352 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Megtekintése teljes képernyőn"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Kilépéshez csúsztassa ujját fentről lefelé."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Értem"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Kész"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Óra kör alakú csúszkája"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Perc kör alakú csúszkája"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 138d810..825924c 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Լիաէկրան դիտում"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Դուրս գալու համար վերևից սահահարվածեք դեպի ներքև:"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Պարզ է"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Պատրաստ է"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ժամերի ընտրություն թվատախտակից"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Րոպեների ընտրություն թվատախտակից"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b02345a..8768e4d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Melihat layar penuh"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Untuk keluar, geser layar ke bawah dari atas."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Mengerti"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Selesai"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Penggeser putar jam"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Penggeser putar menit"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 77df331..9a27d8d 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Notar allan skjáinn"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Strjúktu niður frá efri brún til að hætta."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ég skil"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Lokið"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Valskífa fyrir klukkustundir"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Valskífa fyrir mínútur"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 13f265e..8a6ef85 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visualizzazione a schermo intero"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Per uscire, scorri dall\'alto verso il basso."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Fine"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Dispositivo di scorrimento circolare per le ore"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Dispositivo di scorrimento circolare per i minuti"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 30426c9..4ad7c2c 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"צפייה במסך מלא"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"כדי לצאת, פשוט מחליקים אצבע מלמעלה למטה."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"הבנתי"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"סיום"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"מחוון שעות מעגלי"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"מחוון דקות מעגלי"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 2700f02..917f911 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"全画面表示"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"終了するには、上から下にスワイプします。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"完了"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"円形スライダー(時)"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"円形スライダー(分)"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7608199..e8b84e2 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"სრულ ეკრანზე ნახვა"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"გამოსვლისათვის, გაასრიალეთ ზემოდან ქვემოთ."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"გასაგებია"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"დასრულდა"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"საათების წრიული სლაიდერი"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"წუთების წრიული სლაიდერი"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 4dba2d1..306af3a 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Толық экранда көру"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Шығу үшін жоғарыдан төмен қарай сырғытыңыз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Түсінікті"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Дайын"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Сағаттар айналымының қозғалтқышы"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Минут айналымын қозғалтқыш"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 430493c..2f4b516 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"កំពុងមើលពេញអេក្រង់"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ដើម្បីចាកចេញ សូមអូសពីលើចុះក្រោម។"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"យល់ហើយ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"រួចរាល់"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"គ្រាប់រំកិលរង្វង់ម៉ោង"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"គ្រាប់រំកិលរង្វង់នាទី"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index d923937..a04faa5 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"ಪೂರ್ಣ ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ನಿರ್ಗಮಿಸಲು, ಮೇಲಿನಿಂದ ಕೆಳಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ತಿಳಿಯಿತು"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"ಮುಗಿದಿದೆ"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ಗಂಟೆಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ನಿಮಿಷಗಳ ವೃತ್ತಾಕಾರ ಸ್ಲೈಡರ್"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 4df0322..4974f95 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"전체 화면 모드"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"종료하려면 위에서 아래로 스와이프합니다."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"확인"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"완료"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"시간 원형 슬라이더"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"분 원형 슬라이더"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 521c998..cbc29dc 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Толук экран режими"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Чыгуу үчүн экранды ылдый сүрүп коюңуз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Түшүндүм"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Даяр"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Саат жебеси"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Мүнөт жебеси"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index a172576..09b8bfc 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"ການເບິ່ງເຕັມໜ້າຈໍ"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ຫາກຕ້ອງການອອກ, ໃຫ້ຮູດຈາກທາງເທິງລົງມາທາງລຸ່ມ."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ໄດ້ແລ້ວ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"ແລ້ວໆ"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ໂຕໝຸນປັບຊົ່ວໂມງ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ໂຕໝຸນປັບນາທີ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6da22ed..cfc6418 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Peržiūrima viso ekrano režimu"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Jei norite išeiti, perbraukite žemyn iš viršaus."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Supratau"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Atlikta"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Apskritas valandų šliaužiklis"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Apskritas minučių šliaužiklis"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index aeb89a2..4edf968 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Skatīšanās pilnekrāna režīmā"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Lai izietu, no augšdaļas velciet lejup."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Labi"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Gatavs"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Stundu apļveida slīdnis"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Minūšu apļveida slīdnis"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 44b8e46..dbbd585 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Се прикажува на цел екран"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"За да излезете, повлечете одозгора надолу."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Сфатив"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Приказ на часови во кружно движење"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Приказ на минути во кружно движење"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 1b7daec..b59c322 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"പൂർണ്ണ സ്ക്രീനിൽ കാണുന്നു"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"അവസാനിപ്പിക്കാൻ, മുകളിൽ നിന്ന് താഴോട്ട് സ്വൈപ്പ് ചെയ്യുക."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"മനസ്സിലായി"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"പൂർത്തിയാക്കി"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ചാക്രികമായി മണിക്കൂറുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ചാക്രികമായി മിനിറ്റുകൾ ദൃശ്യമാകുന്ന സ്ലൈഡർ"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index dd6b40d..029358b 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Бүтэн дэлгэцээр үзэж байна"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Гарахаар бол дээрээс нь доош нь чирнэ үү."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ойлголоо"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Дууссан"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Цаг гүйлгэгч"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Минут гүйлгэгч"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 6be015a..ad22469 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"पूर्ण स्क्रीनवर पाहत आहात"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"बाहेर पडण्यासाठी, वरून खाली स्वाइप करा."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"समजले"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"पूर्ण झाले"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"तास परिपत्रक स्लायडर"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"मिनिटे परिपत्रक स्लायडर"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 8ac7373..c038505 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Melihat skrin penuh"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Untuk keluar, leret dari atas ke bawah."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Faham"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Selesai"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Penggelangsar bulatan jam"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Penggelangsar bulatan minit"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 8603b28..badd048 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"မျက်နှာပြင်အပြည့် ကြည့်နေသည်"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ထွက်ရန် အပေါ်မှ အောက်သို့ ဆွဲချပါ။"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ရပါပြီ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"ပြီးပါပြီ"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"နာရီရွေးချက်စရာ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"မိနစ်လှည့်သော ရွေ့လျားတန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index fe9f915..023e48f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visning i fullskjerm"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Sveip ned fra toppen for å avslutte."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Skjønner"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Ferdig"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Sirkulær glidebryter for timer"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Sirkulær glidebryter for minutter"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index edeb116..f789ed6 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"पूरा पर्दा हेर्दै"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"बाहिर निस्कन, माथिबाट तल स्वाइप गर्नुहोस्।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"बुझेँ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"भयो"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"घन्टा गोलाकार स्लाइडर"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"मिनेट गोलाकार स्लाइडर"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 6028b91..7cc02fe 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Volledig scherm wordt getoond"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Swipe omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ik snap het"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Klaar"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ronde schuifregelaar voor uren"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Ronde schuifregelaar voor minuten"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 83cb868..1c86c70 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ଦେଖାଯାଉଛି"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ବାହାରିବା ପାଇଁ, ଉପରୁ ତଳକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ବୁଝିଗଲି"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"ହୋଇଗଲା"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ଘଣ୍ଟା ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ମିନିଟ୍ସ ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index d78c6fc..66aca4f 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"ਪੂਰੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦੇਖੋ"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ਬਾਹਰ ਜਾਣ ਲਈ, ਉਪਰੋਂ ਹੇਠਾਂ ਸਵਾਈਪ ਕਰੋ।"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ਸਮਝ ਲਿਆ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"ਹੋ ਗਿਆ"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ਘੰਟੇ ਸਰਕੁਲਰ ਸਲਾਈਡਰ"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ਮਿੰਟ ਸਰਕੁਲਰ ਸਲਾਈਡਰ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a2c06b7..61e3217 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Włączony pełny ekran"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Aby wyjść, przesuń palcem z góry na dół."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Gotowe"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kołowy suwak godzin"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kołowy suwak minut"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 9768208..91f0a07 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visualização em tela cheia"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Para sair, deslize de cima para baixo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendi"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Concluído"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Controle deslizante circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Controle deslizante circular dos minutos"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 6d7f391..03bc705 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visualização de ecrã inteiro"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Para sair, deslize rapidamente para baixo a partir da parte superior."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Concluído"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Controlo de deslize circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Controlo de deslize circular dos minutos"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 9768208..91f0a07 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visualização em tela cheia"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Para sair, deslize de cima para baixo."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Entendi"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Concluído"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Controle deslizante circular das horas"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Controle deslizante circular dos minutos"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 83fba3f..38ba48d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Vizualizare pe ecran complet"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Pentru a ieși, glisează de sus în jos."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Am înțeles"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Terminat"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Selector circular pentru ore"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Selector circular pentru minute"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 713e67d..93cbae2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Полноэкранный режим"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Чтобы выйти, проведите по экрану сверху вниз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"ОК"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Выбор часов на циферблате"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Выбор минут на циферблате"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 8605c67..d79d0b8 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"මුළු තිරය බලමින්"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"ඉවත් වීමට, ඉහළ සිට පහළට ස්වයිප් කරන්න"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"වැටහුණි"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"අවසන්"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"පැය කවාකාර සර්පනය"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"මිනිත්තු කවාකාර සර්පනය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 63ff006..092827f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Zobrazenie na celú obrazovku"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Ukončíte potiahnutím zhora nadol."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Dobre"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Hotovo"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kruhový posúvač hodín"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kruhový posúvač minút"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e0026a6..f557823 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Vklopljen je celozaslonski način"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Zaprete ga tako, da z vrha s prstom povlečete navzdol."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Razumem"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Dokončano"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Okrogli drsnik za ure"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Okrogli drsnik za minute"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 47e208d..7875ea2 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Po shikon ekranin e plotë"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Për të dalë, rrëshqit nga lart poshtë."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"E kuptova"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"U krye"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Rrëshqitësi rrethor i orëve"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Rrëshqitësi rrethor i minutave"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index f606c8f2c..f3c758c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1841,6 +1841,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Приказује се цео екран"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Да бисте изашли, превуците надоле одозго."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Важи"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Кружни клизач за сате"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Кружни клизач за минуте"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d79049c..7e920d8 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Visar på fullskärm"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Svep nedåt från skärmens överkant för att avsluta."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Klart"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Cirkelreglage för timmar"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Cirkelreglage för minuter"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 180293f..d380436 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Unatazama skrini nzima"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Ili kuondoka, telezesha kidole kutoka juu hadi chini."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Nimeelewa"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Imekamilika"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Kitelezi cha mviringo wa saa"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Kitelezi cha mviringo wa dakika"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 92f0b0a..aee945d 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"முழுத் திரையில் காட்டுகிறது"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"வெளியேற, மேலிருந்து கீழே ஸ்வைப் செய்யவும்"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"புரிந்தது"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"முடிந்தது"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"மணிநேர வட்ட வடிவ ஸ்லைடர்"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"நிமிடங்களுக்கான வட்டவடிவ ஸ்லைடர்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 4e287c1..7d6b3cd 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"ఫుల్-స్క్రీన్లో వీక్షిస్తున్నారు"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"నిష్క్రమించడానికి, పై నుండి క్రిందికి స్వైప్ చేయండి."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"అర్థమైంది"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"పూర్తయింది"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"గంటల వృత్తాకార స్లయిడర్"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"నిమిషాల వృత్తాకార స్లయిడర్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a14b574..852aef0 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"กำลังดูแบบเต็มหน้าจอ"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"หากต้องการออก ให้เลื่อนลงจากด้านบน"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"รับทราบ"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"เสร็จสิ้น"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"ตัวเลื่อนหมุนระบุชั่วโมง"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"ตัวเลื่อนหมุนระบุนาที"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 349a39b..7540fcd 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Panonood sa full screen"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Upang lumabas, mag-swipe mula sa itaas pababa."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Nakuha ko"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Tapos na"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Pabilog na slider ng mga oras"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Pabilog na slider ng mga minuto"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 4e8c5ef..10501d6 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Tam ekran olarak görüntüleme"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Çıkmak için yukarıdan aşağıya doğru hızlıca kaydırın."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Anladım"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Bitti"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Saat kaydırma çemberi"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Dakika kaydırma çemberi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b62e4a3..eecc6e2 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1842,6 +1842,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Перегляд на весь екран"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Щоб вийти, проведіть пальцем зверху вниз."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Готово"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Вибір годин на циферблаті"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Вибір хвилин на циферблаті"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index e3783c3..feea70c 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"پوری اسکرین میں دیکھ رہے ہیں"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"خارج ہونے کیلئے اوپر سے نیچے سوائپ کریں۔"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"سمجھ آ گئی"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"ہو گیا"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"گھنٹوں کا سرکلر سلائیڈر"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"منٹس سرکلر سلائیڈر"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 4a23c25..de858e7 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Butun ekranli rejim"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Chiqish uchun tepadan pastga torting."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Tayyor"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Doiradan soatni tanlang"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Doiradan daqiqani tanlang"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e27495f..05acca6 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Xem toàn màn hình"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Để thoát, hãy vuốt từ trên cùng xuống dưới."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"OK"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Xong"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Thanh trượt giờ hình tròn"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Thanh trượt phút hình tròn"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1c419fc..604e09a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"目前处于全屏模式"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"要退出,请从顶部向下滑动。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"知道了"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"完成"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"小时转盘"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"分钟转盘"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index cc4d15e..85124a4 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"開啟全螢幕"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"由頂部向下滑動即可退出。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"知道了"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"完成"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"小時環形滑桿"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"分鐘環形滑桿"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index b4b6c3b..9207ce2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"以全螢幕檢視"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"如要退出,請從畫面頂端向下滑動。"</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"知道了"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"完成"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"小時數環狀滑桿"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"分鐘數環狀滑桿"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index d40fd0a..5d5d14c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1840,6 +1840,10 @@
<string name="immersive_cling_title" msgid="2307034298721541791">"Ukubuka isikrini esigcwele"</string>
<string name="immersive_cling_description" msgid="7092737175345204832">"Ukuze uphume, swayiphela phansi kusuka phezulu."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ngiyitholile"</string>
+ <!-- no translation found for display_rotation_camera_compat_toast_after_rotation (7600891546249829854) -->
+ <skip />
+ <!-- no translation found for display_rotation_camera_compat_toast_in_split_screen (8393302456336805466) -->
+ <skip />
<string name="done_label" msgid="7283767013231718521">"Kwenziwe"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Amahora weslayidi esiyindingilizi"</string>
<string name="minute_picker_description" msgid="9029797023621927294">"Amaminithi weslayidi esiyindingilizi"</string>
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 4b27bf2..fe296c7 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -18,7 +18,6 @@
<bool name="kg_enable_camera_default_widget">true</bool>
<bool name="kg_center_small_widgets_vertically">false</bool>
<bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool>
- <bool name="kg_wake_on_acquire_start">false</bool>
<bool name="action_bar_embed_tabs">true</bool>
<bool name="split_action_bar_is_narrow">true</bool>
<bool name="preferences_prefer_dual_pane">false</bool>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a6be07d..73518dc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -652,6 +652,16 @@
The default is false. -->
<bool name="config_lidControlsSleep">false</bool>
+ <!-- The device states (supplied by DeviceStateManager) that should be treated as open by the
+ device fold controller. Default is empty. -->
+ <integer-array name="config_openDeviceStates">
+ <!-- Example:
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ -->
+ </integer-array>
+
<!-- The device states (supplied by DeviceStateManager) that should be treated as folded by the
display fold controller. Default is empty. -->
<integer-array name="config_foldedDeviceStates">
@@ -672,6 +682,16 @@
-->
</integer-array>
+ <!-- The device states (supplied by DeviceStateManager) that should be treated as a rear display
+ state. Default is empty. -->
+ <integer-array name="config_rearDisplayDeviceStates">
+ <!-- Example:
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ -->
+ </integer-array>
+
<!-- Indicates whether the window manager reacts to half-fold device states by overriding
rotation. -->
<bool name="config_windowManagerHalfFoldAutoRotateOverride">false</bool>
@@ -964,6 +984,12 @@
<!-- Boolean indicating whether light mode is allowed when DWB is turned on. -->
<bool name="config_displayWhiteBalanceLightModeAllowed">true</bool>
+ <!-- Device states where the sensor based rotation values should be reversed around the Z axis
+ for the default display.
+ TODO(b/265312193): Remove this workaround when this bug is fixed.-->
+ <integer-array name="config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis">
+ </integer-array>
+
<!-- Indicate available ColorDisplayManager.COLOR_MODE_xxx. -->
<integer-array name="config_availableColorModes">
<!-- Example:
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9410e06..ba54183 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5154,6 +5154,14 @@
<!-- Cling help message confirmation button when hiding the navigation bar entering immersive mode [CHAR LIMIT=30] -->
<string name="immersive_cling_positive">Got it</string>
+ <!-- Text on a toast shown after the system rotates the screen for camera app
+ compatibility. [CHAR LIMIT=NONE] -->
+ <string name="display_rotation_camera_compat_toast_after_rotation">Rotate for a better view</string>
+
+ <!-- Text on a toast shown when a camera view is started within the app that may not be able
+ to display the camera preview correctly while in split screen. [CHAR LIMIT=NONE] -->
+ <string name="display_rotation_camera_compat_toast_in_split_screen">Exit split screen for a better view</string>
+
<!-- Label for button to confirm chosen date or time [CHAR LIMIT=30] -->
<string name="done_label">Done</string>
<!--
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index be9f6d2..b7621da 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2841,7 +2841,6 @@
<java-symbol type="dimen" name="fast_scroller_minimum_touch_target" />
<java-symbol type="array" name="config_cdma_international_roaming_indicators" />
<java-symbol type="string" name="kg_text_message_separator" />
- <java-symbol type="bool" name="kg_wake_on_acquire_start" />
<java-symbol type="bool" name="config_use_sim_language_file" />
<java-symbol type="bool" name="config_LTE_eri_for_network_name" />
@@ -3437,6 +3436,11 @@
<java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
<java-symbol type="bool" name="config_displayWhiteBalanceLightModeAllowed" />
+ <!-- Device states where the sensor based rotation values should be reversed around the Z axis
+ for the default display.
+ TODO(b/265312193): Remove this workaround when this bug is fixed.-->
+ <java-symbol type="array" name="config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis" />
+
<!-- Default first user restrictions -->
<java-symbol type="array" name="config_defaultFirstUserRestrictions" />
@@ -4015,8 +4019,10 @@
<java-symbol type="integer" name="config_maxScanTasksForHomeVisibility" />
<!-- For Foldables -->
+ <java-symbol type="array" name="config_openDeviceStates" />
<java-symbol type="array" name="config_foldedDeviceStates" />
<java-symbol type="array" name="config_halfFoldedDeviceStates" />
+ <java-symbol type="array" name="config_rearDisplayDeviceStates" />
<java-symbol type="bool" name="config_windowManagerHalfFoldAutoRotateOverride" />
<java-symbol type="array" name="config_deviceStatesOnWhichToWakeUp" />
<java-symbol type="array" name="config_deviceStatesOnWhichToSleep" />
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index f47d9c6..1cf819a 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -3331,6 +3331,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "1015746067": {
+ "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"1022095595": {
"message": "TaskFragment info changed name=%s",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml
index 416287d..53a8bb1 100644
--- a/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml
+++ b/libs/WindowManager/Shell/res/drawable/desktop_mode_decor_title.xml
@@ -17,5 +17,4 @@
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
- <corners android:radius="20dp" />
</shape>
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml
index 2a4cc02..da31a46 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml
@@ -17,26 +17,14 @@
<com.android.wm.shell.windowdecor.WindowDecorLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/desktop_mode_caption"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
android:background="@drawable/desktop_mode_decor_title">
<Button
- style="@style/CaptionButtonStyle"
- android:id="@+id/back_button"
- android:contentDescription="@string/back_button_text"
- android:background="@drawable/decor_back_button_dark"
- />
- <Button
android:id="@+id/caption_handle"
android:layout_width="128dp"
android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
android:contentDescription="@string/handle_text"
android:background="@drawable/decor_handle_dark"/>
- <Button
- style="@style/CaptionButtonStyle"
- android:id="@+id/close_window"
- android:contentDescription="@string/close_button_text"
- android:background="@drawable/decor_close_button_dark"/>
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 3d50d22..35c5871 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik buite ’n program om dit te herposisioneer"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Het dit"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vou uit vir meer inligting."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimeer"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Maak klein"</string>
<string name="close_button_text" msgid="2913281996024033299">"Maak toe"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 70304aa..b6b99e5 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ቦታውን ለመቀየር ከመተግበሪያው ውጪ ሁለቴ መታ ያድርጉ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ገባኝ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ለተጨማሪ መረጃ ይዘርጉ።"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"አስፋ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"አሳንስ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ዝጋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 0f74aab..7b2aded 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"انقر مرّتين خارج تطبيق لتغيير موضعه."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"حسنًا"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"التوسيع للحصول على مزيد من المعلومات"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"تكبير"</string>
<string name="minimize_button_text" msgid="271592547935841753">"تصغير"</string>
<string name="close_button_text" msgid="2913281996024033299">"إغلاق"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index a0213f4..11a7e32 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"এপ্টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ বাহিৰত দুবাৰ টিপক"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুজি পালোঁ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"অধিক তথ্যৰ বাবে বিস্তাৰ কৰক।"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string>
<string name="minimize_button_text" msgid="271592547935841753">"মিনিমাইজ কৰক"</string>
<string name="close_button_text" msgid="2913281996024033299">"বন্ধ কৰক"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index f842bfe..d3268b3 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tətbiqin yerini dəyişmək üçün kənarına iki dəfə toxunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ətraflı məlumat üçün genişləndirin."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Böyüdün"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Kiçildin"</string>
<string name="close_button_text" msgid="2913281996024033299">"Bağlayın"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 540ae7c..89bb9d8 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste promenili njenu poziciju"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za još informacija."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Uvećajte"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Umanjite"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zatvorite"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index bea7538..0961f30 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двойчы націсніце экран па-за праграмай, каб перамясціць яе"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Зразумела"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгарнуць для дадатковай інфармацыі"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Разгарнуць"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Згарнуць"</string>
<string name="close_button_text" msgid="2913281996024033299">"Закрыць"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 59915e6..6a0648b 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Докоснете два пъти извън дадено приложение, за да промените позицията му"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Разбрах"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгъване за още информация."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Увеличаване"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Намаляване"</string>
<string name="close_button_text" msgid="2913281996024033299">"Затваряне"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 63c9684..5e80104 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"কোনও অ্যাপের স্থান পরিবর্তন করতে তার বাইরে ডবল ট্যাপ করুন"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"বুঝেছি"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"আরও তথ্যের জন্য বড় করুন।"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"বড় করুন"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ছোট করুন"</string>
<string name="close_button_text" msgid="2913281996024033299">"বন্ধ করুন"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index b725efe..3978991 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da promijenite njen položaj"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Razumijem"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za više informacija."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Želite li ponovno pokrenuti za bolji pregled?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Možete ponovno pokrenuti aplikaciju tako da bolje izgleda na zaslonu, no mogli biste izgubiti napredak ili sve nespremljene promjene"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Odustani"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Pokreni ponovno"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovno"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziranje"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimiziranje"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zatvaranje"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 4383916..3b070d8 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Fes doble toc fora d\'una aplicació per canviar-ne la posició"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entesos"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Desplega per obtenir més informació."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximitza"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimitza"</string>
<string name="close_button_text" msgid="2913281996024033299">"Tanca"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index e5cb26f..3606eaa 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikaci změníte její umístění"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozbalením zobrazíte další informace."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovat"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalizovat"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zavřít"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 46f7c69..487d412 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryk to gange uden for en app for at justere dens placering"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Udvid for at få flere oplysninger."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimér"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string>
<string name="close_button_text" msgid="2913281996024033299">"Luk"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 1269d36..0ec59e7 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Außerhalb einer App doppeltippen, um die Position zu ändern"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ok"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Für weitere Informationen maximieren."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximieren"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimieren"</string>
<string name="close_button_text" msgid="2913281996024033299">"Schließen"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index f8a69ef..ba3e743 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Πατήστε δύο φορές έξω από μια εφαρμογή για να αλλάξετε τη θέση της"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Το κατάλαβα"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ανάπτυξη για περισσότερες πληροφορίες."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Μεγιστοποίηση"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Ελαχιστοποίηση"</string>
<string name="close_button_text" msgid="2913281996024033299">"Κλείσιμο"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 8e46c3e..e29b01b 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Restart for a better view?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"You can restart the app so that it looks better on your screen, but you may lose your progress or any unsaved changes"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 7cbbf64..9228c59 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Restart for a better view?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"You can restart the app so it looks better on your screen, but you may lose your progress or any unsaved changes"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don’t show again"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximize"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimize"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 8e46c3e..e29b01b 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Restart for a better view?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"You can restart the app so that it looks better on your screen, but you may lose your progress or any unsaved changes"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 8e46c3e..e29b01b 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Restart for a better view?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"You can restart the app so that it looks better on your screen, but you may lose your progress or any unsaved changes"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimise"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index b2720be..cf23114 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Restart for a better view?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"You can restart the app so it looks better on your screen, but you may lose your progress or any unsaved changes"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancel"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don’t show again"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximize"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimize"</string>
<string name="close_button_text" msgid="2913281996024033299">"Close"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 47445a7..63e8046 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Presiona dos veces fuera de una app para cambiar su ubicación"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expande para obtener más información."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 6c45231..9c5aa92 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dos veces fuera de una aplicación para cambiarla de posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mostrar más información"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index a8dc08c..f7eafbd 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Topeltpuudutage rakendusest väljaspool, et selle asendit muuta"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Laiendage lisateabe saamiseks."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimeeri"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimeeri"</string>
<string name="close_button_text" msgid="2913281996024033299">"Sule"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 9fbf0a0..a46095a 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren kanpoaldea"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ados"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Informazio gehiago lortzeko, zabaldu hau."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Aplikazioa berrabiarazi nahi duzu itxura hobea izan dezan?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Aplikazioa berrabiarazi egin dezakezu itxura hobea izan dezan, baina agian garapena edo gorde gabeko aldaketak galduko dituzu"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Utzi"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Berrabiarazi"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ez erakutsi berriro"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizatu"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizatu"</string>
<string name="close_button_text" msgid="2913281996024033299">"Itxi"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index e7cb5f4..ea8fafe 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"برای جابهجا کردن برنامه، بیرون از آن دوضربه بزنید"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجهام"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"برای اطلاعات بیشتر، گسترده کنید."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"بزرگ کردن"</string>
<string name="minimize_button_text" msgid="271592547935841753">"کوچک کردن"</string>
<string name="close_button_text" msgid="2913281996024033299">"بستن"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 86199f3..298de64 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kaksoisnapauta sovelluksen ulkopuolella, jos haluat siirtää sitä"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Katso lisätietoja laajentamalla."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Suurenna"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Pienennä"</string>
<string name="close_button_text" msgid="2913281996024033299">"Sulje"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 1f3ac9e..36b40bd 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Touchez deux fois à côté d\'une application pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développer pour en savoir plus."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fermer"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index f1dbb35..7f3f914 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Appuyez deux fois en dehors d\'une appli pour la repositionner"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développez pour obtenir plus d\'informations"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fermer"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 6e215a1..3d5265f 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toca dúas veces fóra da aplicación para cambiala de posición"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Despregar para obter máis información."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Pechar"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index ad086bb..d2e5a82 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બહાર બે વાર ટૅપ કરો"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"સમજાઈ ગયું"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"વધુ માહિતી માટે મોટું કરો."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"બહેતર વ્યૂ માટે ફરીથી શરૂ કરીએ?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"તમે ઍપને ફરીથી શરૂ કરી શકો છો, જેથી તે તમારી સ્ક્રીન પર વધુ સારી રીતે દેખાય, પરંતુ આમ કરવાથી તમે તમારી ઍપ પર કરી હોય એવી કોઈ પ્રક્રિયાની પ્રગતિ અથવા સાચવ્યા ન હોય એવો કોઈપણ ફેરફાર ગુમાવી શકો છો"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"રદ કરો"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"ફરી શરૂ કરો"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ફરીથી બતાવશો નહીં"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"મોટું કરો"</string>
<string name="minimize_button_text" msgid="271592547935841753">"નાનું કરો"</string>
<string name="close_button_text" msgid="2913281996024033299">"બંધ કરો"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index bed39fb..b217978 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बाहर दो बार टैप करें"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ज़्यादा जानकारी के लिए बड़ा करें."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"बड़ा करें"</string>
<string name="minimize_button_text" msgid="271592547935841753">"विंडो छोटी करें"</string>
<string name="close_button_text" msgid="2913281996024033299">"बंद करें"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 1446e70..bbd95f7 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvaput dodirnite izvan aplikacije da biste je premjestili"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Shvaćam"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite da biste saznali više."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Želite li ponovno pokrenuti za bolji pregled?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Možete ponovno pokrenuti aplikaciju tako da bolje izgleda na zaslonu, no mogli biste izgubiti napredak ili sve nespremljene promjene"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Odustani"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Pokreni ponovno"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovno"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziraj"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimiziraj"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zatvori"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 221c329..1bb2213 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Koppintson duplán az alkalmazáson kívül az áthelyezéséhez"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Értem"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kibontással további információkhoz juthat."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Újraindítja a jobb megjelenítés érdekében?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Újraindíthatja az alkalmazást a képernyőn való jobb megjelenítés érdekében, de elveszítheti az előrehaladását és az esetleges nem mentett változásokat"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Mégse"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Újraindítás"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne jelenjen meg többé"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Teljes méret"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Kis méret"</string>
<string name="close_button_text" msgid="2913281996024033299">"Bezárás"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 7be9941..7d556b2 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Եղավ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ծավալեք՝ ավելին իմանալու համար։"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Ծավալել"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Ծալել"</string>
<string name="close_button_text" msgid="2913281996024033299">"Փակել"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 4e760ef..b51dc00 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketuk dua kali di luar aplikasi untuk mengubah posisinya"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Luaskan untuk melihat informasi selengkapnya."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimalkan"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalkan"</string>
<string name="close_button_text" msgid="2913281996024033299">"Tutup"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 50d4ee7..d924c47 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ýttu tvisvar utan við forrit til að færa það"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ég skil"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Stækka til að sjá frekari upplýsingar."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Stækka"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minnka"</string>
<string name="close_button_text" msgid="2913281996024033299">"Loka"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index d2595f7..98d1b45 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tocca due volte fuori da un\'app per riposizionarla"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Espandi per avere ulteriori informazioni."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Vuoi riavviare per migliorare la visualizzazione?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Puoi riavviare l\'app affinché venga visualizzata meglio sullo schermo, ma potresti perdere i tuoi progressi o eventuali modifiche non salvate"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annulla"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Riavvia"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrare più"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Ingrandisci"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Riduci a icona"</string>
<string name="close_button_text" msgid="2913281996024033299">"Chiudi"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 883596e..d116257 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"צריך להקיש הקשה כפולה מחוץ לאפליקציה כדי למקם אותה מחדש"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"הבנתי"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"מרחיבים כדי לקבל מידע נוסף."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"הגדלה"</string>
<string name="minimize_button_text" msgid="271592547935841753">"מזעור"</string>
<string name="close_button_text" msgid="2913281996024033299">"סגירה"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 6bb22a2..548d63c 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"位置を変えるにはアプリの外側をダブルタップしてください"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"開くと詳細が表示されます。"</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"再起動して画面をすっきりさせますか?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"アプリを再起動して画面をすっきりさせることはできますが、進捗状況が失われ、保存されていない変更が消える可能性があります"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"キャンセル"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"再起動"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"次回から表示しない"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"閉じる"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 6cf7d78..1b0aeb1 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ორმაგად შეეხეთ აპის გარშემო სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"გასაგებია"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"დამატებითი ინფორმაციისთვის გააფართოეთ."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"მაქსიმალურად გაშლა"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ჩაკეცვა"</string>
<string name="close_button_text" msgid="2913281996024033299">"დახურვა"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 216619a..02560ca 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Қолданбаның орнын өзгерту үшін одан тыс жерді екі рет түртіңіз."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түсінікті"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толығырақ ақпарат алу үшін терезені жайыңыз."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Жаю"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Кішірейту"</string>
<string name="close_button_text" msgid="2913281996024033299">"Жабу"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 79aca62..32ca8e3 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ចុចពីរដងនៅក្រៅកម្មវិធី ដើម្បីប្ដូរទីតាំងកម្មវិធីនោះ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"យល់ហើយ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ពង្រីកដើម្បីទទួលបានព័ត៌មានបន្ថែម។"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"ពង្រីក"</string>
<string name="minimize_button_text" msgid="271592547935841753">"បង្រួម"</string>
<string name="close_button_text" msgid="2913281996024033299">"បិទ"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 9e9333e..fc17093 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಹೊರಗೆ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ಸರಿ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ವಿಸ್ತೃತಗೊಳಿಸಿ."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"ಹಿಗ್ಗಿಸಿ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ಕುಗ್ಗಿಸಿ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ಮುಚ್ಚಿರಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index f9b495a..844a9fa 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"앱 위치를 조정하려면 앱 외부를 두 번 탭합니다."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"추가 정보는 펼쳐서 확인하세요."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"최대화"</string>
<string name="minimize_button_text" msgid="271592547935841753">"최소화"</string>
<string name="close_button_text" msgid="2913281996024033299">"닫기"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 0858cfc..765cfe2 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Колдонмону жылдыруу үчүн сырт жагын эки жолу таптаңыз"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Түшүндүм"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толук маалымат алуу үчүн жайып көрүңүз."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Чоңойтуу"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Кичирейтүү"</string>
<string name="close_button_text" msgid="2913281996024033299">"Жабуу"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 8e42aa3..2923b9f 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ແຕະສອງເທື່ອໃສ່ນອກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ຂະຫຍາຍເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ຫຍໍ້ລົງ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ປິດ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index dc99690..0d276ec 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dukart palieskite už programos ribų, kad pakeistumėte jos poziciją"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Supratau"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Išskleiskite, jei reikia daugiau informacijos."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Paleisti iš naujo, kad būtų geresnis vaizdas?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Galite iš naujo paleisti programą, kad ji geriau atrodytų ekrane, bet galite prarasti eigą ir neišsaugotus pakeitimus"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Atšaukti"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Paleisti iš naujo"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Daugiau neberodyti"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Padidinti"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Sumažinti"</string>
<string name="close_button_text" msgid="2913281996024033299">"Uždaryti"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index bd2eef4..3f6b04a 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Lai pārvietotu lietotni, veiciet dubultskārienu ārpus lietotnes"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Labi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Izvērsiet, lai iegūtu plašāku informāciju."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimizēt"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizēt"</string>
<string name="close_button_text" msgid="2913281996024033299">"Aizvērt"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index d133654..526093d 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Допрете двапати надвор од некоја апликација за да ја преместите"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Сфатив"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширете за повеќе информации."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Да се рестартира за подобар приказ?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Може да ја рестартирате апликацијата за да изгледа подобро на екранот, но може да го изгубите напредокот или незачуваните промени"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Откажи"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартирај"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не прикажувај повторно"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Зголеми"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Минимизирај"</string>
<string name="close_button_text" msgid="2913281996024033299">"Затвори"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 16927bf..084b6ee 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ അതിന് പുറത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"മനസ്സിലായി"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"കൂടുതൽ വിവരങ്ങൾക്ക് വികസിപ്പിക്കുക."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"വലുതാക്കുക"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ചെറുതാക്കുക"</string>
<string name="close_button_text" msgid="2913281996024033299">"അടയ്ക്കുക"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 264f9a0..6c1c0b5 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Аппыг дахин байрлуулахын тулд гадна талд нь хоёр товшино"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ойлголоо"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Нэмэлт мэдээлэл авах бол дэлгэнэ үү."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Томруулах"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Багасгах"</string>
<string name="close_button_text" msgid="2913281996024033299">"Хаах"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 7a475ed..5d07175 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या बाहेर दोनदा टॅप करा"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"समजले"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"अधिक माहितीसाठी विस्तार करा."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"मोठे करा"</string>
<string name="minimize_button_text" msgid="271592547935841753">"लहान करा"</string>
<string name="close_button_text" msgid="2913281996024033299">"बंद करा"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index be1dc24..80efab8 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketik dua kali di luar apl untuk menempatkan semula apl itu"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kembangkan untuk mendapatkan maklumat lanjut."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimumkan"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimumkan"</string>
<string name="close_button_text" msgid="2913281996024033299">"Tutup"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 7b2b7c5..be0815e 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"နေရာပြန်ချရန် အက်ပ်အပြင်ဘက်ကို နှစ်ချက်တို့ပါ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"နားလည်ပြီ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"နောက်ထပ်အချက်အလက်များအတွက် ချဲ့နိုင်သည်။"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"ချဲ့ရန်"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ချုံ့ရန်"</string>
<string name="close_button_text" msgid="2913281996024033299">"ပိတ်ရန်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 3e18b49..8d15086 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dobbelttrykk utenfor en app for å flytte den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Greit"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vis for å få mer informasjon."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimer"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string>
<string name="close_button_text" msgid="2913281996024033299">"Lukk"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 4b10f5a..52336aa 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको बाहिर डबल ट्याप गर्नुहोस्"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"बुझेँ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"थप जानकारी प्राप्त गर्न चाहनुहुन्छ भने एक्स्पान्ड गर्नुहोस्।"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"ठुलो बनाउनुहोस्"</string>
<string name="minimize_button_text" msgid="271592547935841753">"मिनिमाइज गर्नुहोस्"</string>
<string name="close_button_text" msgid="2913281996024033299">"बन्द गर्नुहोस्"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index b056483..ef06ede 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dubbeltik naast een app om deze opnieuw te positioneren"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Uitvouwen voor meer informatie."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximaliseren"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimaliseren"</string>
<string name="close_button_text" msgid="2913281996024033299">"Sluiten"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 5fd81f4..0a8882d 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହାର ବାହାରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ବୁଝିଗଲି"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ଅଧିକ ସୂଚନା ପାଇଁ ବିସ୍ତାର କରନ୍ତୁ।"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"ବଡ଼ କରନ୍ତୁ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ଛୋଟ କରନ୍ତୁ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ବନ୍ଦ କରନ୍ତୁ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index ada79d1..62f15bf 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਬਾਹਰ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ਸਮਝ ਲਿਆ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਵਿਸਤਾਰ ਕਰੋ।"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"ਵੱਡਾ ਕਰੋ"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ਛੋਟਾ ਕਰੋ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ਬੰਦ ਕਰੋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index a97fd5c..d82f60f6 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Kliknij dwukrotnie poza aplikacją, aby ją przenieść"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozwiń, aby wyświetlić więcej informacji."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksymalizuj"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalizuj"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zamknij"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 8edcddf..a94d157 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Reiniciar para melhorar a visualização?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Você pode reiniciar o app para melhorar a visualização dele, mas talvez perca seu progresso ou mudanças não salvas"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fechar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index e0636d4..7435faf 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de uma app para a reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expandir para obter mais informações"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fechar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 8edcddf..a94d157 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Toque duas vezes fora de um app para reposicionar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Reiniciar para melhorar a visualização?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Você pode reiniciar o app para melhorar a visualização dele, mas talvez perca seu progresso ou mudanças não salvas"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Cancelar"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string>
<string name="close_button_text" msgid="2913281996024033299">"Fechar"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 9227216..8286002 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Atinge de două ori lângă o aplicație pentru a o repoziționa"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extinde pentru mai multe informații"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximizează"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizează"</string>
<string name="close_button_text" msgid="2913281996024033299">"Închide"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index f5fa1a4..934a0da 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Чтобы переместить приложение, дважды нажмите рядом с ним."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОК"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Развернуть, чтобы узнать больше."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Развернуть"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Свернуть"</string>
<string name="close_button_text" msgid="2913281996024033299">"Закрыть"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 53e52f2..e408655 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"යෙදුමක් නැවත ස්ථානගත කිරීමට පිටතින් දෙවරක් තට්ටු කරන්න"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"තේරුණා"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"වැඩිදුර තොරතුරු සඳහා දිග හරින්න"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"විහිදන්න"</string>
<string name="minimize_button_text" msgid="271592547935841753">"කුඩා කරන්න"</string>
<string name="close_button_text" msgid="2913281996024033299">"වසන්න"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index f004fd4..4fb4672 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvojitým klepnutím mimo aplikácie zmeníte jej pozíciu"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Dobre"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Po rozbalení sa dozviete viac."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovať"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimalizovať"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zavrieť"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index c4808059..ac9c2be 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Dvakrat se dotaknite zunaj aplikacije, če jo želite prestaviti."</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"V redu"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Razširitev za več informacij"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimiraj"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimiraj"</string>
<string name="close_button_text" msgid="2913281996024033299">"Zapri"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index b59d4db..f4fc5e7 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Trokit dy herë jashtë një aplikacioni për ta ripozicionuar"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Zgjeroje për më shumë informacion."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Rinis për një pamje më të mirë?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Mund të rinisësh aplikacionin në mënyrë që të duket më mirë në ekranin tënd, por mund të humbësh progresin ose çdo ndryshim të paruajtur"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Anulo"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"Rinis"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Mos e shfaq përsëri"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"Maksimizo"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimizo"</string>
<string name="close_button_text" msgid="2913281996024033299">"Mbyll"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 78d74d74..e692830 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Двапут додирните изван апликације да бисте променили њену позицију"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширите за још информација."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Увећајте"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Умањите"</string>
<string name="close_button_text" msgid="2913281996024033299">"Затворите"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index cda3040..ba57851 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Tryck snabbt två gånger utanför en app för att flytta den"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Utöka för mer information."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Utöka"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Minimera"</string>
<string name="close_button_text" msgid="2913281996024033299">"Stäng"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index fee34eb..43b415c 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Gusa mara mbili nje ya programu ili uihamishe"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Nimeelewa"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Panua ili upate maelezo zaidi."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Panua"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Punguza"</string>
<string name="close_button_text" msgid="2913281996024033299">"Funga"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 49f128d..3e65964 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"ஆப்ஸை இடம் மாற்ற அதன் வெளியில் இருமுறை தட்டலாம்"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"சரி"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"கூடுதல் தகவல்களுக்கு விரிவாக்கலாம்."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"பெரிதாக்கும்"</string>
<string name="minimize_button_text" msgid="271592547935841753">"சிறிதாக்கும்"</string>
<string name="close_button_text" msgid="2913281996024033299">"மூடும்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index f0c8be5..7d09fc4 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"యాప్ స్థానాన్ని మార్చడానికి దాని వెలుపల డబుల్-ట్యాప్ చేయండి"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"మరింత సమాచారం కోసం విస్తరించండి."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"గరిష్టీకరించండి"</string>
<string name="minimize_button_text" msgid="271592547935841753">"కుదించండి"</string>
<string name="close_button_text" msgid="2913281996024033299">"మూసివేయండి"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 2437e03..a9100e8 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"แตะสองครั้งด้านนอกแอปเพื่อเปลี่ยนตำแหน่ง"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"รับทราบ"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ขยายเพื่อดูข้อมูลเพิ่มเติม"</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"รีสตาร์ทเพื่อรับมุมมองที่ดียิ่งขึ้นใช่ไหม"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"คุณรีสตาร์ทแอปเพื่อรับมุมมองที่ดียิ่งขึ้นบนหน้าจอได้ แต่ความคืบหน้าและการเปลี่ยนแปลงใดๆ ที่ไม่ได้บันทึกอาจหายไป"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"ยกเลิก"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"รีสตาร์ท"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ไม่ต้องแสดงข้อความนี้อีก"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"ขยายใหญ่สุด"</string>
<string name="minimize_button_text" msgid="271592547935841753">"ย่อ"</string>
<string name="close_button_text" msgid="2913281996024033299">"ปิด"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 86ef757..7a4232c 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -82,6 +82,11 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Mag-double tap sa labas ng app para baguhin ang posisyon nito"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"I-expand para sa higit pang impormasyon."</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"I-restart para sa mas magandang hitsura?"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Puwede mong i-restart ang app para maging mas maganda ang itsura nito sa iyong screen, pero posibleng mawala ang pag-usad mo o anumang hindi na-save na pagbabago"</string>
+ <string name="letterbox_restart_cancel" msgid="1342209132692537805">"Kanselahin"</string>
+ <string name="letterbox_restart_restart" msgid="8529976234412442973">"I-restart"</string>
+ <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Huwag nang ipakita ulit"</string>
<string name="maximize_button_text" msgid="1650859196290301963">"I-maximize"</string>
<string name="minimize_button_text" msgid="271592547935841753">"I-minimize"</string>
<string name="close_button_text" msgid="2913281996024033299">"Isara"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index c4060cc..015cfc8 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Yeniden konumlandırmak için uygulamanın dışına iki kez dokunun"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Daha fazla bilgi için genişletin."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Ekranı Kapla"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Küçült"</string>
<string name="close_button_text" msgid="2913281996024033299">"Kapat"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 166041d..1ed9069 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Щоб перемістити додаток, двічі торкніться області поза ним"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ОK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Розгорніть, щоб дізнатися більше."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Збільшити"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Згорнути"</string>
<string name="close_button_text" msgid="2913281996024033299">"Закрити"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index ca6a937..a6d9bdb 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس ایپ کے باہر دو بار تھپتھپائیں"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"سمجھ آ گئی"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"مزید معلومات کے لیے پھیلائیں۔"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"بڑا کریں"</string>
<string name="minimize_button_text" msgid="271592547935841753">"چھوٹا کریں"</string>
<string name="close_button_text" msgid="2913281996024033299">"بند کریں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 8f173d5..0bbdf4f 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Qayta joylash uchun ilova tashqarisiga ikki marta bosing"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Batafsil axborot olish uchun kengaytiring."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Yoyish"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Kichraytirish"</string>
<string name="close_button_text" msgid="2913281996024033299">"Yopish"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 1d5b9d6..d8e1318 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Nhấn đúp bên ngoài ứng dụng để đặt lại vị trí"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mở rộng để xem thêm thông tin."</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Phóng to"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Thu nhỏ"</string>
<string name="close_button_text" msgid="2913281996024033299">"Đóng"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 87f2973..88d6aa6 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在某个应用外连续点按两次,即可调整它的位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展开即可了解详情。"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"关闭"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index f9b22d22..daed258 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕按兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳情。"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"關閉"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 1438e52..afcaf23 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕觸兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"我知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳細資訊。"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
<string name="minimize_button_text" msgid="271592547935841753">"最小化"</string>
<string name="close_button_text" msgid="2913281996024033299">"關閉"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index e9238dc..cef00e4 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -82,6 +82,16 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Thepha kabili ngaphandle kwe-app ukuze uyimise kabusha"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Ngiyezwa"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Nweba ukuze uthole ulwazi olwengeziwe"</string>
+ <!-- no translation found for letterbox_restart_dialog_title (8543049527871033505) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_description (6096946078246557848) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_cancel (1342209132692537805) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_restart (8529976234412442973) -->
+ <skip />
+ <!-- no translation found for letterbox_restart_dialog_checkbox_title (5252918008140768386) -->
+ <skip />
<string name="maximize_button_text" msgid="1650859196290301963">"Khulisa"</string>
<string name="minimize_button_text" msgid="271592547935841753">"Nciphisa"</string>
<string name="close_button_text" msgid="2913281996024033299">"Vala"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index a1da649..8908959 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -364,8 +364,8 @@
<!-- Height of button (32dp) + 2 * margin (5dp each). -->
<dimen name="freeform_decor_caption_height">42dp</dimen>
- <!-- Width of buttons (64dp) + handle (128dp) + padding (24dp total). -->
- <dimen name="freeform_decor_caption_width">216dp</dimen>
+ <!-- Width of buttons (32dp each) + padding (128dp total). -->
+ <dimen name="freeform_decor_caption_menu_width">256dp</dimen>
<dimen name="freeform_resize_handle">30dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index c14704d..fe95d04 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -215,8 +215,14 @@
: taskStableBounds.right - taskBounds.left - mLayout.getMeasuredWidth();
final int positionY = taskStableBounds.bottom - taskBounds.top
- mLayout.getMeasuredHeight();
-
+ // To secure a proper visualisation, we hide the layout while updating the position of
+ // the {@link SurfaceControl} it belongs.
+ final int oldVisibility = mLayout.getVisibility();
+ if (oldVisibility == View.VISIBLE) {
+ mLayout.setVisibility(View.GONE);
+ }
updateSurfacePosition(positionX, positionY);
+ mLayout.setVisibility(oldVisibility);
}
private void updateVisibilityOfViews() {
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 f77ac81..476a7ec 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
@@ -174,7 +174,7 @@
final CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
- windowDecoration.setDragResizeCallback(taskPositioner);
+ windowDecoration.setDragPositioningCallback(taskPositioner);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT);
setupCaptionColor(taskInfo, windowDecoration);
@@ -185,17 +185,17 @@
private final int mTaskId;
private final WindowContainerToken mTaskToken;
- private final DragResizeCallback mDragResizeCallback;
+ private final DragPositioningCallback mDragPositioningCallback;
private final DragDetector mDragDetector;
private int mDragPointerId = -1;
private CaptionTouchEventListener(
RunningTaskInfo taskInfo,
- DragResizeCallback dragResizeCallback) {
+ DragPositioningCallback dragPositioningCallback) {
mTaskId = taskInfo.taskId;
mTaskToken = taskInfo.token;
- mDragResizeCallback = dragResizeCallback;
+ mDragPositioningCallback = dragPositioningCallback;
mDragDetector = new DragDetector(this);
}
@@ -247,20 +247,20 @@
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mDragPointerId = e.getPointerId(0);
- mDragResizeCallback.onDragResizeStart(
+ mDragPositioningCallback.onDragPositioningStart(
0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
break;
}
case MotionEvent.ACTION_MOVE: {
int dragPointerIdx = e.findPointerIndex(mDragPointerId);
- mDragResizeCallback.onDragResizeMove(
+ mDragPositioningCallback.onDragPositioningMove(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
int dragPointerIdx = e.findPointerIndex(mDragPointerId);
- mDragResizeCallback.onDragResizeEnd(
+ mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
break;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index f94fbfc..060dc4e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -47,7 +47,7 @@
private View.OnClickListener mOnCaptionButtonClickListener;
private View.OnTouchListener mOnCaptionTouchListener;
- private DragResizeCallback mDragResizeCallback;
+ private DragPositioningCallback mDragPositioningCallback;
private DragResizeInputListener mDragResizeListener;
private DragDetector mDragDetector;
@@ -78,8 +78,8 @@
mOnCaptionTouchListener = onCaptionTouchListener;
}
- void setDragResizeCallback(DragResizeCallback dragResizeCallback) {
- mDragResizeCallback = dragResizeCallback;
+ void setDragPositioningCallback(DragPositioningCallback dragPositioningCallback) {
+ mDragPositioningCallback = dragPositioningCallback;
}
void setDragDetector(DragDetector dragDetector) {
@@ -151,7 +151,7 @@
mChoreographer,
mDisplay.getDisplayId(),
mDecorationContainerSurface,
- mDragResizeCallback);
+ mDragPositioningCallback);
}
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
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 bd3afa9..606cf28 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
@@ -209,17 +209,17 @@
private final int mTaskId;
private final WindowContainerToken mTaskToken;
- private final DragResizeCallback mDragResizeCallback;
+ private final DragPositioningCallback mDragPositioningCallback;
private final DragDetector mDragDetector;
private int mDragPointerId = -1;
private DesktopModeTouchEventListener(
RunningTaskInfo taskInfo,
- DragResizeCallback dragResizeCallback) {
+ DragPositioningCallback dragPositioningCallback) {
mTaskId = taskInfo.taskId;
mTaskToken = taskInfo.token;
- mDragResizeCallback = dragResizeCallback;
+ mDragPositioningCallback = dragPositioningCallback;
mDragDetector = new DragDetector(this);
}
@@ -227,11 +227,7 @@
public void onClick(View v) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
final int id = v.getId();
- if (id == R.id.close_window) {
- mTaskOperations.closeTask(mTaskToken);
- } else if (id == R.id.back_button) {
- mTaskOperations.injectBackKey();
- } else if (id == R.id.caption_handle) {
+ if (id == R.id.caption_handle) {
decoration.createHandleMenu();
} else if (id == R.id.desktop_button) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
@@ -287,13 +283,13 @@
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mDragPointerId = e.getPointerId(0);
- mDragResizeCallback.onDragResizeStart(
+ mDragPositioningCallback.onDragPositioningStart(
0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
break;
}
case MotionEvent.ACTION_MOVE: {
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
- mDragResizeCallback.onDragResizeMove(
+ mDragPositioningCallback.onDragPositioningMove(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
break;
}
@@ -302,7 +298,7 @@
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
final int statusBarHeight = mDisplayController
.getDisplayLayout(taskInfo.displayId).stableInsets().top;
- mDragResizeCallback.onDragResizeEnd(
+ mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
if (e.getRawY(dragPointerIdx) <= statusBarHeight) {
if (DesktopModeStatus.isProto2Enabled()) {
@@ -561,7 +557,7 @@
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
- windowDecoration.setDragResizeCallback(taskPositioner);
+ windowDecoration.setDragPositioningCallback(taskPositioner);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT);
incrementEventReceiverTasks(taskInfo.displayId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 9550937..744c18f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -25,7 +25,6 @@
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.PointF;
-import android.graphics.Rect;
import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.view.Choreographer;
@@ -55,11 +54,12 @@
private View.OnClickListener mOnCaptionButtonClickListener;
private View.OnTouchListener mOnCaptionTouchListener;
- private DragResizeCallback mDragResizeCallback;
+ private DragPositioningCallback mDragPositioningCallback;
private DragResizeInputListener mDragResizeListener;
private DragDetector mDragDetector;
private RelayoutParams mRelayoutParams = new RelayoutParams();
+ private final int mCaptionMenuWidthId = R.dimen.freeform_decor_caption_menu_width;
private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
new WindowDecoration.RelayoutResult<>();
@@ -90,8 +90,8 @@
mOnCaptionTouchListener = onCaptionTouchListener;
}
- void setDragResizeCallback(DragResizeCallback dragResizeCallback) {
- mDragResizeCallback = dragResizeCallback;
+ void setDragPositioningCallback(DragPositioningCallback dragPositioningCallback) {
+ mDragPositioningCallback = dragPositioningCallback;
}
void setDragDetector(DragDetector dragDetector) {
@@ -131,22 +131,10 @@
mRelayoutParams.mRunningTaskInfo = taskInfo;
mRelayoutParams.mLayoutResId = R.layout.desktop_mode_window_decor;
mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
- mRelayoutParams.mCaptionWidthId = R.dimen.freeform_decor_caption_width;
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
if (isDragResizeable) {
mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId);
}
- final Resources resources = mDecorWindowContext.getResources();
- final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
- final int captionHeight = loadDimensionPixelSize(resources,
- mRelayoutParams.mCaptionHeightId);
- final int captionWidth = loadDimensionPixelSize(resources,
- mRelayoutParams.mCaptionWidthId);
- final int captionLeft = taskBounds.width() / 2
- - captionWidth / 2;
- final int captionTop = taskBounds.top
- <= captionHeight / 2 ? 0 : -captionHeight / 2;
- mRelayoutParams.setCaptionPosition(captionLeft, captionTop);
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
@@ -191,7 +179,7 @@
mChoreographer,
mDisplay.getDisplayId(),
mDecorationContainerSurface,
- mDragResizeCallback);
+ mDragPositioningCallback);
}
final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext())
@@ -212,10 +200,6 @@
private void setupRootView() {
final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption);
caption.setOnTouchListener(mOnCaptionTouchListener);
- final View close = caption.findViewById(R.id.close_window);
- close.setOnClickListener(mOnCaptionButtonClickListener);
- final View back = caption.findViewById(R.id.back_button);
- back.setOnClickListener(mOnCaptionButtonClickListener);
final View handle = caption.findViewById(R.id.caption_handle);
handle.setOnTouchListener(mOnCaptionTouchListener);
handle.setOnClickListener(mOnCaptionButtonClickListener);
@@ -230,8 +214,6 @@
desktop.setOnClickListener(mOnCaptionButtonClickListener);
final View split = menu.findViewById(R.id.split_screen_button);
split.setOnClickListener(mOnCaptionButtonClickListener);
- final View more = menu.findViewById(R.id.more_button);
- more.setOnClickListener(mOnCaptionButtonClickListener);
}
/**
@@ -264,10 +246,6 @@
void setButtonVisibility(boolean visible) {
final int visibility = visible ? View.VISIBLE : View.GONE;
final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption);
- final View back = caption.findViewById(R.id.back_button);
- final View close = caption.findViewById(R.id.close_window);
- back.setVisibility(visibility);
- close.setVisibility(visibility);
final int buttonTintColorRes =
mDesktopActive ? R.color.decor_button_dark_color
: R.color.decor_button_light_color;
@@ -297,14 +275,18 @@
void createHandleMenu() {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
final Resources resources = mDecorWindowContext.getResources();
- final int x = mRelayoutParams.mCaptionX;
- final int y = mRelayoutParams.mCaptionY;
- final int width = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionWidthId);
- final int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
+ final int captionWidth = mTaskInfo.getConfiguration()
+ .windowConfiguration.getBounds().width();
+ final int menuWidth = loadDimensionPixelSize(
+ resources, mCaptionMenuWidthId);
+ final int height = loadDimensionPixelSize(
+ resources, mRelayoutParams.mCaptionHeightId);
+ final int x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2)
+ - mResult.mDecorContainerOffsetX;
+ final int y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY;
String namePrefix = "Caption Menu";
- mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t,
- x - mResult.mDecorContainerOffsetX, y - mResult.mDecorContainerOffsetY,
- width, height);
+ mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y,
+ menuWidth, height);
mSyncQueue.runInSync(transaction -> {
transaction.merge(t);
t.close();
@@ -370,7 +352,7 @@
if (mResult.mRootView == null) return false;
final PointF inputPoint = offsetCaptionLocation(ev);
final View view = mResult.mRootView.findViewById(layoutId);
- return view != null && view.pointInView(inputPoint.x, inputPoint.y, 0);
+ return view != null && pointInView(view, inputPoint.x, inputPoint.y);
}
boolean checkTouchEventInHandle(MotionEvent ev) {
@@ -387,32 +369,39 @@
*/
void checkClickEvent(MotionEvent ev) {
if (mResult.mRootView == null) return;
- final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption);
- final PointF inputPoint = offsetCaptionLocation(ev);
if (!isHandleMenuActive()) {
+ final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption);
final View handle = caption.findViewById(R.id.caption_handle);
- clickIfPointInView(inputPoint, handle);
+ clickIfPointInView(new PointF(ev.getX(), ev.getY()), handle);
} else {
final View menu = mHandleMenu.mWindowViewHost.getView();
+ final int captionWidth = mTaskInfo.getConfiguration().windowConfiguration
+ .getBounds().width();
+ final int menuX = mRelayoutParams.mCaptionX + (captionWidth / 2)
+ - (menu.getWidth() / 2);
+ final PointF inputPoint = new PointF(ev.getX() - menuX, ev.getY());
final View fullscreen = menu.findViewById(R.id.fullscreen_button);
if (clickIfPointInView(inputPoint, fullscreen)) return;
final View desktop = menu.findViewById(R.id.desktop_button);
if (clickIfPointInView(inputPoint, desktop)) return;
final View split = menu.findViewById(R.id.split_screen_button);
if (clickIfPointInView(inputPoint, split)) return;
- final View more = menu.findViewById(R.id.more_button);
- clickIfPointInView(inputPoint, more);
}
}
private boolean clickIfPointInView(PointF inputPoint, View v) {
- if (v.pointInView(inputPoint.x - v.getLeft(), inputPoint.y, 0)) {
+ if (pointInView(v, inputPoint.x, inputPoint.y)) {
mOnCaptionButtonClickListener.onClick(v);
return true;
}
return false;
}
+ private boolean pointInView(View v, float x, float y) {
+ return v != null && v.getLeft() <= x && v.getRight() >= x
+ && v.getTop() <= y && v.getBottom() >= y;
+ }
+
@Override
public void close() {
closeDragResizeListener();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeCallback.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
similarity index 76%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeCallback.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
index ee160a1..0191c60 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeCallback.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallback.java
@@ -19,28 +19,28 @@
/**
* Callback called when receiving drag-resize or drag-move related input events.
*/
-public interface DragResizeCallback {
+public interface DragPositioningCallback {
/**
- * Called when a drag resize starts.
+ * Called when a drag-resize or drag-move starts.
*
* @param ctrlType {@link TaskPositioner.CtrlType} indicating the direction of resizing, use
* {@code 0} to indicate it's a move
- * @param x x coordinate in window decoration coordinate system where the drag resize starts
- * @param y y coordinate in window decoration coordinate system where the drag resize starts
+ * @param x x coordinate in window decoration coordinate system where the drag starts
+ * @param y y coordinate in window decoration coordinate system where the drag starts
*/
- void onDragResizeStart(@TaskPositioner.CtrlType int ctrlType, float x, float y);
+ void onDragPositioningStart(@TaskPositioner.CtrlType int ctrlType, float x, float y);
/**
- * Called when the pointer moves during a drag resize.
+ * Called when the pointer moves during a drag-resize or drag-move.
* @param x x coordinate in window decoration coordinate system of the new pointer location
* @param y y coordinate in window decoration coordinate system of the new pointer location
*/
- void onDragResizeMove(float x, float y);
+ void onDragPositioningMove(float x, float y);
/**
- * Called when a drag resize stops.
+ * Called when a drag-resize or drag-move stops.
* @param x x coordinate in window decoration coordinate system where the drag resize stops
* @param y y coordinate in window decoration coordinate system where the drag resize stops
*/
- void onDragResizeEnd(float x, float y);
+ void onDragPositioningEnd(float x, float y);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 2963763..7d954ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -62,7 +62,7 @@
private final SurfaceControl mDecorationSurface;
private final InputChannel mInputChannel;
private final TaskResizeInputEventReceiver mInputEventReceiver;
- private final com.android.wm.shell.windowdecor.DragResizeCallback mCallback;
+ private final DragPositioningCallback mCallback;
private int mWidth;
private int mHeight;
@@ -83,7 +83,7 @@
Choreographer choreographer,
int displayId,
SurfaceControl decorationSurface,
- DragResizeCallback callback) {
+ DragPositioningCallback callback) {
mInputManager = context.getSystemService(InputManager.class);
mHandler = handler;
mChoreographer = choreographer;
@@ -293,7 +293,7 @@
float rawX = e.getRawX(0);
float rawY = e.getRawY(0);
int ctrlType = calculateCtrlType(isTouch, x, y);
- mCallback.onDragResizeStart(ctrlType, rawX, rawY);
+ mCallback.onDragPositioningStart(ctrlType, rawX, rawY);
result = true;
}
break;
@@ -305,7 +305,7 @@
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
float rawX = e.getRawX(dragPointerIndex);
float rawY = e.getRawY(dragPointerIndex);
- mCallback.onDragResizeMove(rawX, rawY);
+ mCallback.onDragPositioningMove(rawX, rawY);
result = true;
break;
}
@@ -313,7 +313,7 @@
case MotionEvent.ACTION_CANCEL: {
if (mShouldHandleEvents) {
int dragPointerIndex = e.findPointerIndex(mDragPointerId);
- mCallback.onDragResizeEnd(
+ mCallback.onDragPositioningEnd(
e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
}
mShouldHandleEvents = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
index 8cd2a59..d3f9227 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
@@ -23,7 +23,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
-class TaskPositioner implements DragResizeCallback {
+class TaskPositioner implements DragPositioningCallback {
@IntDef({CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
@interface CtrlType {}
@@ -38,8 +38,8 @@
private final WindowDecoration mWindowDecoration;
private final Rect mTaskBoundsAtDragStart = new Rect();
- private final PointF mResizeStartPoint = new PointF();
- private final Rect mResizeTaskBounds = new Rect();
+ private final PointF mRepositionStartPoint = new PointF();
+ private final Rect mRepositionTaskBounds = new Rect();
private boolean mHasMoved = false;
private int mCtrlType;
@@ -57,7 +57,7 @@
}
@Override
- public void onDragResizeStart(int ctrlType, float x, float y) {
+ public void onDragPositioningStart(int ctrlType, float x, float y) {
mHasMoved = false;
mDragStartListener.onDragStart(mWindowDecoration.mTaskInfo.taskId);
@@ -65,11 +65,11 @@
mTaskBoundsAtDragStart.set(
mWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds());
- mResizeStartPoint.set(x, y);
+ mRepositionStartPoint.set(x, y);
}
@Override
- public void onDragResizeMove(float x, float y) {
+ public void onDragPositioningMove(float x, float y) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (changeBounds(wct, x, y)) {
// The task is being resized, send the |dragResizing| hint to core with the first
@@ -84,7 +84,7 @@
}
@Override
- public void onDragResizeEnd(float x, float y) {
+ public void onDragPositioningEnd(float x, float y) {
// |mHasMoved| being false means there is no real change to the task bounds in WM core, so
// we don't need a WCT to finish it.
if (mHasMoved) {
@@ -96,42 +96,44 @@
mCtrlType = CTRL_TYPE_UNDEFINED;
mTaskBoundsAtDragStart.setEmpty();
- mResizeStartPoint.set(0, 0);
+ mRepositionStartPoint.set(0, 0);
mHasMoved = false;
}
private boolean changeBounds(WindowContainerTransaction wct, float x, float y) {
- // |mResizeTaskBounds| is the bounds last reported if |mHasMoved| is true. If it's not true,
- // we can compare it against |mTaskBoundsAtDragStart|.
- final int oldLeft = mHasMoved ? mResizeTaskBounds.left : mTaskBoundsAtDragStart.left;
- final int oldTop = mHasMoved ? mResizeTaskBounds.top : mTaskBoundsAtDragStart.top;
- final int oldRight = mHasMoved ? mResizeTaskBounds.right : mTaskBoundsAtDragStart.right;
- final int oldBottom = mHasMoved ? mResizeTaskBounds.bottom : mTaskBoundsAtDragStart.bottom;
+ // |mRepositionTaskBounds| is the bounds last reported if |mHasMoved| is true. If it's not
+ // true, we can compare it against |mTaskBoundsAtDragStart|.
+ final int oldLeft = mHasMoved ? mRepositionTaskBounds.left : mTaskBoundsAtDragStart.left;
+ final int oldTop = mHasMoved ? mRepositionTaskBounds.top : mTaskBoundsAtDragStart.top;
+ final int oldRight = mHasMoved ? mRepositionTaskBounds.right : mTaskBoundsAtDragStart.right;
+ final int oldBottom =
+ mHasMoved ? mRepositionTaskBounds.bottom : mTaskBoundsAtDragStart.bottom;
- final float deltaX = x - mResizeStartPoint.x;
- final float deltaY = y - mResizeStartPoint.y;
- mResizeTaskBounds.set(mTaskBoundsAtDragStart);
+ final float deltaX = x - mRepositionStartPoint.x;
+ final float deltaY = y - mRepositionStartPoint.y;
+ mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
if ((mCtrlType & CTRL_TYPE_LEFT) != 0) {
- mResizeTaskBounds.left += deltaX;
+ mRepositionTaskBounds.left += deltaX;
}
if ((mCtrlType & CTRL_TYPE_RIGHT) != 0) {
- mResizeTaskBounds.right += deltaX;
+ mRepositionTaskBounds.right += deltaX;
}
if ((mCtrlType & CTRL_TYPE_TOP) != 0) {
- mResizeTaskBounds.top += deltaY;
+ mRepositionTaskBounds.top += deltaY;
}
if ((mCtrlType & CTRL_TYPE_BOTTOM) != 0) {
- mResizeTaskBounds.bottom += deltaY;
+ mRepositionTaskBounds.bottom += deltaY;
}
if (mCtrlType == CTRL_TYPE_UNDEFINED) {
- mResizeTaskBounds.offset((int) deltaX, (int) deltaY);
+ mRepositionTaskBounds.offset((int) deltaX, (int) deltaY);
}
- if (oldLeft == mResizeTaskBounds.left && oldTop == mResizeTaskBounds.top
- && oldRight == mResizeTaskBounds.right && oldBottom == mResizeTaskBounds.bottom) {
+ if (oldLeft == mRepositionTaskBounds.left && oldTop == mRepositionTaskBounds.top
+ && oldRight == mRepositionTaskBounds.right
+ && oldBottom == mRepositionTaskBounds.bottom) {
return false;
}
- wct.setBounds(mWindowDecoration.mTaskInfo.token, mResizeTaskBounds);
+ wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
return true;
}
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 7f85988..62b72f3 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
@@ -252,9 +252,7 @@
}
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
- final int captionWidth = params.mCaptionWidthId == Resources.ID_NULL
- ? taskBounds.width()
- : loadDimensionPixelSize(resources, params.mCaptionWidthId);
+ final int captionWidth = taskBounds.width();
startT.setPosition(
mCaptionContainerSurface,
@@ -428,7 +426,6 @@
RunningTaskInfo mRunningTaskInfo;
int mLayoutResId;
int mCaptionHeightId;
- int mCaptionWidthId;
int mShadowRadiusId;
int mOutsetTopId;
@@ -454,7 +451,6 @@
void reset() {
mLayoutResId = Resources.ID_NULL;
mCaptionHeightId = Resources.ID_NULL;
- mCaptionWidthId = Resources.ID_NULL;
mShadowRadiusId = Resources.ID_NULL;
mOutsetTopId = Resources.ID_NULL;
diff --git a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
index 8949a75..27d40b2 100644
--- a/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/tests/unittest/res/values/dimen.xml
@@ -17,7 +17,7 @@
<resources>
<!-- Resources used in WindowDecorationTests -->
<dimen name="test_freeform_decor_caption_height">32dp</dimen>
- <dimen name="test_freeform_decor_caption_width">216dp</dimen>
+ <dimen name="test_freeform_decor_caption_menu_width">216dp</dimen>
<dimen name="test_window_decor_left_outset">10dp</dimen>
<dimen name="test_window_decor_top_outset">20dp</dimen>
<dimen name="test_window_decor_right_outset">30dp</dimen>
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
index 324940e..0c5edc3f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIWindowManagerTest.java
@@ -28,6 +28,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -359,14 +360,14 @@
mWindowManager.updateVisibility(/* canShow= */ false);
verify(mWindowManager, never()).createLayout(anyBoolean());
- verify(mLayout).setVisibility(View.GONE);
+ verify(mLayout, atLeastOnce()).setVisibility(View.GONE);
// Show button.
doReturn(View.GONE).when(mLayout).getVisibility();
mWindowManager.updateVisibility(/* canShow= */ true);
verify(mWindowManager, never()).createLayout(anyBoolean());
- verify(mLayout).setVisibility(View.VISIBLE);
+ verify(mLayout, atLeastOnce()).setVisibility(View.VISIBLE);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
index 804c416..f185a8a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/TaskPositionerTest.kt
@@ -66,13 +66,13 @@
@Test
fun testDragResize_notMove_skipsTransactionOnEnd() {
- taskPositioner.onDragResizeStart(
+ taskPositioner.onDragPositioningStart(
CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
- taskPositioner.onDragResizeEnd(
+ taskPositioner.onDragPositioningEnd(
STARTING_BOUNDS.left.toFloat() + 10,
STARTING_BOUNDS.top.toFloat() + 10
)
@@ -87,18 +87,18 @@
@Test
fun testDragResize_noEffectiveMove_skipsTransactionOnMoveAndEnd() {
- taskPositioner.onDragResizeStart(
+ taskPositioner.onDragPositioningStart(
CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
- taskPositioner.onDragResizeMove(
+ taskPositioner.onDragPositioningMove(
STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
- taskPositioner.onDragResizeEnd(
+ taskPositioner.onDragPositioningEnd(
STARTING_BOUNDS.left.toFloat() + 10,
STARTING_BOUNDS.top.toFloat() + 10
)
@@ -113,13 +113,13 @@
@Test
fun testDragResize_hasEffectiveMove_issuesTransactionOnMoveAndEnd() {
- taskPositioner.onDragResizeStart(
+ taskPositioner.onDragPositioningStart(
CTRL_TYPE_TOP or CTRL_TYPE_RIGHT,
STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
- taskPositioner.onDragResizeMove(
+ taskPositioner.onDragPositioningMove(
STARTING_BOUNDS.left.toFloat() + 10,
STARTING_BOUNDS.top.toFloat()
)
@@ -133,7 +133,7 @@
}
})
- taskPositioner.onDragResizeEnd(
+ taskPositioner.onDragPositioningEnd(
STARTING_BOUNDS.left.toFloat() + 10,
STARTING_BOUNDS.top.toFloat() + 10
)
@@ -150,7 +150,7 @@
@Test
fun testDragResize_move_skipsDragResizingFlag() {
- taskPositioner.onDragResizeStart(
+ taskPositioner.onDragPositioningStart(
CTRL_TYPE_UNDEFINED, // Move
STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
@@ -159,12 +159,12 @@
// Move the task 10px to the right.
val newX = STARTING_BOUNDS.left.toFloat() + 10
val newY = STARTING_BOUNDS.top.toFloat()
- taskPositioner.onDragResizeMove(
+ taskPositioner.onDragPositioningMove(
newX,
newY
)
- taskPositioner.onDragResizeEnd(newX, newY)
+ taskPositioner.onDragPositioningEnd(newX, newY)
verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
return@argThat wct.changes.any { (token, change) ->
@@ -177,7 +177,7 @@
@Test
fun testDragResize_resize_setsDragResizingFlag() {
- taskPositioner.onDragResizeStart(
+ taskPositioner.onDragPositioningStart(
CTRL_TYPE_RIGHT, // Resize right
STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
@@ -186,12 +186,12 @@
// Resize the task by 10px to the right.
val newX = STARTING_BOUNDS.right.toFloat() + 10
val newY = STARTING_BOUNDS.top.toFloat()
- taskPositioner.onDragResizeMove(
+ taskPositioner.onDragPositioningMove(
newX,
newY
)
- taskPositioner.onDragResizeEnd(newX, newY)
+ taskPositioner.onDragPositioningEnd(newX, newY)
verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
return@argThat wct.changes.any { (token, change) ->
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 ec4f17f..2f5263c 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
@@ -107,6 +107,7 @@
private SurfaceControl.Transaction mMockSurfaceControlFinishT;
private SurfaceControl.Transaction mMockSurfaceControlAddWindowT;
private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
+ private int mCaptionMenuWidthId;
@Before
public void setUp() {
@@ -116,8 +117,7 @@
mRelayoutParams.mLayoutResId = 0;
mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
- // Caption should have fixed width except in testLayoutResultCalculation_fullWidthCaption()
- mRelayoutParams.mCaptionWidthId = R.dimen.test_freeform_decor_caption_width;
+ mCaptionMenuWidthId = R.dimen.test_freeform_decor_caption_menu_width;
mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
@@ -240,7 +240,7 @@
verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
verify(captionContainerSurfaceBuilder).setContainerLayer();
verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
- verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 432, 64);
+ verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
@@ -248,7 +248,7 @@
verify(mMockSurfaceControlViewHost)
.setView(same(mMockView),
argThat(lp -> lp.height == 64
- && lp.width == 432
+ && lp.width == 300
&& (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0));
if (ViewRootImpl.CAPTION_ON_SHELL) {
verify(mMockView).setTaskFocusState(true);
@@ -484,7 +484,6 @@
final SurfaceControl taskSurface = mock(SurfaceControl.class);
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
- mRelayoutParams.mCaptionWidthId = Resources.ID_NULL;
windowDecor.relayout(taskInfo);
verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
@@ -558,7 +557,7 @@
final Resources resources = mDecorWindowContext.getResources();
int x = mRelayoutParams.mCaptionX;
int y = mRelayoutParams.mCaptionY;
- int width = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionWidthId);
+ int width = loadDimensionPixelSize(resources, mCaptionMenuWidthId);
int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
String name = "Test Window";
WindowDecoration.AdditionalWindow additionalWindow =
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 798688e..2c139b7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1337,12 +1337,8 @@
public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
- try {
- service.setVolumeIndexForAttributes(attr, index, flags,
- getContext().getOpPackageName(), getContext().getAttributionTag());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ setVolumeGroupVolumeIndex(groupId, index, flags);
}
/**
@@ -1361,11 +1357,8 @@
public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
- try {
- return service.getVolumeIndexForAttributes(attr);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ return getVolumeGroupVolumeIndex(groupId);
}
/**
@@ -1382,11 +1375,8 @@
public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
- try {
- return service.getMaxVolumeIndexForAttributes(attr);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ return getVolumeGroupMaxVolumeIndex(groupId);
}
/**
@@ -1403,8 +1393,168 @@
public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
+ int groupId = getVolumeGroupIdForAttributes(attr);
+ return getVolumeGroupMinVolumeIndex(groupId);
+ }
+
+ /**
+ * Returns the volume group id associated to the given {@link AudioAttributes}.
+ *
+ * @param attributes The {@link AudioAttributes} to consider.
+ * @return {@link android.media.audiopolicy.AudioVolumeGroup} id supporting the given
+ * {@link AudioAttributes} if found,
+ * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise.
+ * @hide
+ */
+ public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
+ Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
+ return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes,
+ /* fallbackOnDefault= */ false);
+ }
+
+ /**
+ * Sets the volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link getVolumeGroupIdForAttributes} to retrieve the volume group
+ * id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @param index The volume index to set. See
+ * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value
+ * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value.
+ * @param flags One or more flags.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void setVolumeGroupVolumeIndex(int groupId, int index, int flags) {
+ final IAudioService service = getService();
try {
- return service.getMinVolumeIndexForAttributes(attr);
+ service.setVolumeGroupVolumeIndex(groupId, index, flags,
+ getContext().getOpPackageName(), getContext().getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link getVolumeGroupIdForAttributes} to retrieve the volume group
+ * id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The current volume index for the stream.
+ * @hide
+ */
+ @IntRange(from = 0)
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public int getVolumeGroupVolumeIndex(int groupId) {
+ final IAudioService service = getService();
+ try {
+ return service.getVolumeGroupVolumeIndex(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the maximum volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link getVolumeGroupIdForAttributes} to retrieve the volume group
+ * id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The maximum valid volume index for the {@link AudioAttributes}.
+ * @hide
+ */
+ @IntRange(from = 0)
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public int getVolumeGroupMaxVolumeIndex(int groupId) {
+ final IAudioService service = getService();
+ try {
+ return service.getVolumeGroupMaxVolumeIndex(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the minimum volume index for a particular group associated to given id.
+ * <p> Call first in prior {@link getVolumeGroupIdForAttributes} to retrieve the volume group
+ * id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The minimum valid volume index for the {@link AudioAttributes}.
+ * @hide
+ */
+ @IntRange(from = 0)
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public int getVolumeGroupMinVolumeIndex(int groupId) {
+ final IAudioService service = getService();
+ try {
+ return service.getVolumeGroupMinVolumeIndex(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Adjusts the volume of a particular group associated to given id by one step in a direction.
+ * <p> If the volume group is associated to a stream type, it fallbacks on
+ * {@link AudioManager#adjustStreamVolume()} for compatibility reason.
+ * <p> Call first in prior {@link getVolumeGroupIdForAttributes} to retrieve the volume group
+ * id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @param direction The direction to adjust the volume. One of
+ * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
+ * {@link #ADJUST_SAME}.
+ * @param flags One or more flags.
+ * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
+ * is not granted notification policy access.
+ * @hide
+ */
+ public void adjustVolumeGroupVolume(int groupId, int direction, int flags) {
+ IAudioService service = getService();
+ try {
+ service.adjustVolumeGroupVolume(groupId, direction, flags,
+ getContext().getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get last audible volume of the group associated to given id before it was muted.
+ * <p> Call first in prior {@link getVolumeGroupIdForAttributes} to retrieve the volume group
+ * id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return current volume if not muted, volume before muted otherwise.
+ * @hide
+ */
+ @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
+ @IntRange(from = 0)
+ public int getLastAudibleVolumeGroupVolume(int groupId) {
+ IAudioService service = getService();
+ try {
+ return service.getLastAudibleVolumeGroupVolume(groupId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the current mute state for a particular volume group associated to the given id.
+ * <p> Call first in prior {@link getVolumeGroupIdForAttributes} to retrieve the volume group
+ * id supporting the given {@link AudioAttributes}.
+ *
+ * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
+ * @return The mute state for the given {@link android.media.audiopolicy.AudioVolumeGroup} id.
+ * @see #adjustAttributesVolume(AudioAttributes, int, int)
+ * @hide
+ */
+ public boolean isVolumeGroupMuted(int groupId) {
+ IAudioService service = getService();
+ try {
+ return service.isVolumeGroupMuted(groupId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -7687,7 +7837,8 @@
Objects.requireNonNull(device);
try {
if (device.getId() == 0) {
- throw new IllegalArgumentException("In valid device: " + device);
+ Log.w(TAG, "setCommunicationDevice: device not found: " + device);
+ return false;
}
return getService().setCommunicationDevice(mICallBack, device.getId());
} catch (RemoteException e) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index ad933e0..88a0321 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -126,14 +126,20 @@
List<AudioVolumeGroup> getAudioVolumeGroups();
- void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags,
- String callingPackage, in String attributionTag);
+ void setVolumeGroupVolumeIndex(int groupId, int index, int flags, String callingPackage,
+ in String attributionTag);
- int getVolumeIndexForAttributes(in AudioAttributes aa);
+ int getVolumeGroupVolumeIndex(int groupId);
- int getMaxVolumeIndexForAttributes(in AudioAttributes aa);
+ int getVolumeGroupMaxVolumeIndex(int groupId);
- int getMinVolumeIndexForAttributes(in AudioAttributes aa);
+ int getVolumeGroupMinVolumeIndex(int groupId);
+
+ int getLastAudibleVolumeGroupVolume(int groupId);
+
+ boolean isVolumeGroupMuted(int groupId);
+
+ void adjustVolumeGroupVolume(int groupId, int direction, int flags, String callingPackage);
int getLastAudibleStreamVolume(int streamType);
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 31d5967..a792501 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -29,10 +29,10 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* @hide
@@ -142,7 +142,7 @@
*/
public static int getLegacyStreamTypeForStrategyWithAudioAttributes(
@NonNull AudioAttributes audioAttributes) {
- Preconditions.checkNotNull(audioAttributes, "AudioAttributes must not be null");
+ Objects.requireNonNull(audioAttributes, "AudioAttributes must not be null");
for (final AudioProductStrategy productStrategy :
AudioProductStrategy.getAudioProductStrategies()) {
if (productStrategy.supportsAudioAttributes(audioAttributes)) {
@@ -162,6 +162,30 @@
return AudioSystem.STREAM_MUSIC;
}
+ /**
+ * @hide
+ * @param attributes the {@link AudioAttributes} to identify VolumeGroupId with
+ * @param fallbackOnDefault if set, allows to fallback on the default group (e.g. the group
+ * associated to {@link AudioManager#STREAM_MUSIC}).
+ * @return volume group id associated with the given {@link AudioAttributes} if found,
+ * default volume group id if fallbackOnDefault is set
+ * <p>By convention, the product strategy with default attributes will be associated to the
+ * default volume group (e.g. associated to {@link AudioManager#STREAM_MUSIC})
+ * or {@link AudioVolumeGroup#DEFAULT_VOLUME_GROUP} if not found.
+ */
+ public static int getVolumeGroupIdForAudioAttributes(
+ @NonNull AudioAttributes attributes, boolean fallbackOnDefault) {
+ Objects.requireNonNull(attributes, "attributes must not be null");
+ int volumeGroupId = getVolumeGroupIdForAudioAttributesInt(attributes);
+ if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
+ return volumeGroupId;
+ }
+ if (fallbackOnDefault) {
+ return getVolumeGroupIdForAudioAttributesInt(getDefaultAttributes());
+ }
+ return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
+ }
+
private static List<AudioProductStrategy> initializeAudioProductStrategies() {
ArrayList<AudioProductStrategy> apsList = new ArrayList<AudioProductStrategy>();
int status = native_list_audio_product_strategies(apsList);
@@ -192,8 +216,8 @@
*/
private AudioProductStrategy(@NonNull String name, int id,
@NonNull AudioAttributesGroup[] aag) {
- Preconditions.checkNotNull(name, "name must not be null");
- Preconditions.checkNotNull(aag, "AudioAttributesGroups must not be null");
+ Objects.requireNonNull(name, "name must not be null");
+ Objects.requireNonNull(aag, "AudioAttributesGroups must not be null");
mName = name;
mId = id;
mAudioAttributesGroups = aag;
@@ -211,6 +235,15 @@
/**
* @hide
+ * @return the product strategy ID (which is the generalisation of Car Audio Usage / legacy
+ * routing_strategy linked to {@link AudioAttributes#getUsage()}).
+ */
+ @NonNull public String getName() {
+ return mName;
+ }
+
+ /**
+ * @hide
* @return first {@link AudioAttributes} associated to this product strategy.
*/
@SystemApi
@@ -243,7 +276,7 @@
*/
@TestApi
public int getLegacyStreamTypeForAudioAttributes(@NonNull AudioAttributes aa) {
- Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
+ Objects.requireNonNull(aa, "AudioAttributes must not be null");
for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
if (aag.supportsAttributes(aa)) {
return aag.getStreamType();
@@ -260,7 +293,7 @@
*/
@SystemApi
public boolean supportsAudioAttributes(@NonNull AudioAttributes aa) {
- Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
+ Objects.requireNonNull(aa, "AudioAttributes must not be null");
for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
if (aag.supportsAttributes(aa)) {
return true;
@@ -293,7 +326,7 @@
*/
@TestApi
public int getVolumeGroupIdForAudioAttributes(@NonNull AudioAttributes aa) {
- Preconditions.checkNotNull(aa, "AudioAttributes must not be null");
+ Objects.requireNonNull(aa, "AudioAttributes must not be null");
for (final AudioAttributesGroup aag : mAudioAttributesGroups) {
if (aag.supportsAttributes(aa)) {
return aag.getVolumeGroupId();
@@ -302,6 +335,17 @@
return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
}
+ private static int getVolumeGroupIdForAudioAttributesInt(@NonNull AudioAttributes attributes) {
+ Objects.requireNonNull(attributes, "attributes must not be null");
+ for (AudioProductStrategy productStrategy : getAudioProductStrategies()) {
+ int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes);
+ if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
+ return volumeGroupId;
+ }
+ }
+ return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -377,8 +421,8 @@
*/
private static boolean attributesMatches(@NonNull AudioAttributes refAttr,
@NonNull AudioAttributes attr) {
- Preconditions.checkNotNull(refAttr, "refAttr must not be null");
- Preconditions.checkNotNull(attr, "attr must not be null");
+ Objects.requireNonNull(refAttr, "reference AudioAttributes must not be null");
+ Objects.requireNonNull(attr, "requester's AudioAttributes must not be null");
String refFormattedTags = TextUtils.join(";", refAttr.getTags());
String cliFormattedTags = TextUtils.join(";", attr.getTags());
if (refAttr.equals(DEFAULT_ATTRIBUTES)) {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 2f4dd8f..408883e 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1004,9 +1004,10 @@
static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
sp<IDrm> drm = android::DrmUtils::MakeDrm();
+ if (drm == NULL) return env->NewByteArray(0);
+
std::vector<uint8_t> bv;
drm->getSupportedSchemes(bv);
-
jbyteArray jUuidBytes = env->NewByteArray(bv.size());
env->SetByteArrayRegion(jUuidBytes, 0, bv.size(), reinterpret_cast<const jbyte *>(bv.data()));
return jUuidBytes;
diff --git a/packages/PackageInstaller/res/values-pt-rBR/strings.xml b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
index b9e5be8..43dd331 100644
--- a/packages/PackageInstaller/res/values-pt-rBR/strings.xml
+++ b/packages/PackageInstaller/res/values-pt-rBR/strings.xml
@@ -53,7 +53,7 @@
<string name="uninstall_application_title" msgid="4045420072401428123">"Desinstalar app"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar atualização"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> é parte do seguinte app:"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"Quer desinstalar este app?"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar este app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string>
diff --git a/packages/PackageInstaller/res/values-pt/strings.xml b/packages/PackageInstaller/res/values-pt/strings.xml
index b9e5be8..43dd331 100644
--- a/packages/PackageInstaller/res/values-pt/strings.xml
+++ b/packages/PackageInstaller/res/values-pt/strings.xml
@@ -53,7 +53,7 @@
<string name="uninstall_application_title" msgid="4045420072401428123">"Desinstalar app"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Desinstalar atualização"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> é parte do seguinte app:"</string>
- <string name="uninstall_application_text" msgid="3816830743706143980">"Quer desinstalar este app?"</string>
+ <string name="uninstall_application_text" msgid="3816830743706143980">"Você quer desinstalar este app?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"Quer desinstalar este app para "<b>"todos"</b>" os usuários? O aplicativo e os dados dele serão removidos para "<b>"todos"</b>" os usuários do dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"Quer desinstalar este app para o usuário <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Você quer desinstalar esse app do seu perfil de trabalho?"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index d6586db..d9d7cc9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -185,6 +185,24 @@
public abstract String getId();
/**
+ * Get disabled reason of device
+ *
+ * @return disabled reason of device
+ */
+ public int getDisableReason() {
+ return -1;
+ }
+
+ /**
+ * Checks if device is has disabled reason
+ *
+ * @return true if device has disabled reason
+ */
+ public boolean hasDisabledReason() {
+ return false;
+ }
+
+ /**
* Checks if device is suggested device from application
*
* @return true if device is suggested device
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index c729b09..17a94b86 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -41,6 +41,7 @@
import androidx.annotation.UiThread
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
+import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "ActivityLaunchAnimator"
@@ -338,13 +339,24 @@
* Return a [Controller] that will animate and expand [view] into the opening window.
*
* Important: The view must be attached to a [ViewGroup] when calling this function and
- * during the animation. For safety, this method will return null when it is not.
+ * during the animation. For safety, this method will return null when it is not. The
+ * view must also implement [LaunchableView], otherwise this method will throw.
*
* Note: The background of [view] should be a (rounded) rectangle so that it can be
* properly animated.
*/
@JvmStatic
fun fromView(view: View, cujType: Int? = null): Controller? {
+ // Make sure the View we launch from implements LaunchableView to avoid visibility
+ // issues.
+ if (view !is LaunchableView) {
+ throw IllegalArgumentException(
+ "An ActivityLaunchAnimator.Controller was created from a View that does " +
+ "not implement LaunchableView. This can lead to subtle bugs where the" +
+ " visibility of the View we are launching from is not what we expected."
+ )
+ }
+
if (view.parent !is ViewGroup) {
Log.e(
TAG,
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index e91a671..b8d78fb 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -40,6 +40,7 @@
import com.android.systemui.animation.back.applyTo
import com.android.systemui.animation.back.floatingSystemSurfacesForSysUi
import com.android.systemui.animation.back.onBackAnimationCallbackFrom
+import java.lang.IllegalArgumentException
import kotlin.math.roundToInt
private const val TAG = "DialogLaunchAnimator"
@@ -157,12 +158,23 @@
* Create a [Controller] that can animate [source] to and from a dialog.
*
* Important: The view must be attached to a [ViewGroup] when calling this function and
- * during the animation. For safety, this method will return null when it is not.
+ * during the animation. For safety, this method will return null when it is not. The
+ * view must also implement [LaunchableView], otherwise this method will throw.
*
* Note: The background of [view] should be a (rounded) rectangle so that it can be
* properly animated.
*/
fun fromView(source: View, cuj: DialogCuj? = null): Controller? {
+ // Make sure the View we launch from implements LaunchableView to avoid visibility
+ // issues.
+ if (source !is LaunchableView) {
+ throw IllegalArgumentException(
+ "A DialogLaunchAnimator.Controller was created from a View that does not " +
+ "implement LaunchableView. This can lead to subtle bugs where the " +
+ "visibility of the View we are launching from is not what we expected."
+ )
+ }
+
if (source.parent !is ViewGroup) {
Log.e(
TAG,
@@ -249,23 +261,6 @@
}
?: controller
- if (
- animatedParent == null &&
- controller is ViewDialogLaunchAnimatorController &&
- controller.source !is LaunchableView
- ) {
- // Make sure the View we launch from implements LaunchableView to avoid visibility
- // issues. Given that we don't own dialog decorViews so we can't enforce it for launches
- // from a dialog.
- // TODO(b/243636422): Throw instead of logging to enforce this.
- Log.w(
- TAG,
- "A dialog was launched from a View that does not implement LaunchableView. This " +
- "can lead to subtle bugs where the visibility of the View we are " +
- "launching from is not what we expected."
- )
- }
-
// Make sure we don't run the launch animation from the same source twice at the same time.
if (openedDialogs.any { it.controller.sourceIdentity == controller.sourceIdentity }) {
Log.e(
@@ -613,10 +608,16 @@
}
// Animate that view with the background. Throw if we didn't find one, because
- // otherwise
- // it's not clear what we should animate.
+ // otherwise it's not clear what we should animate.
+ if (viewGroupWithBackground == null) {
+ error("Unable to find ViewGroup with background")
+ }
+
+ if (viewGroupWithBackground !is LaunchableView) {
+ error("The animated ViewGroup with background must implement LaunchableView")
+ }
+
viewGroupWithBackground
- ?: throw IllegalStateException("Unable to find ViewGroup with background")
} else {
// We will make the dialog window (and therefore its DecorView) fullscreen to make
// it possible to animate outside its bounds.
@@ -639,7 +640,7 @@
FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
)
- val dialogContentWithBackground = FrameLayout(dialog.context)
+ val dialogContentWithBackground = LaunchableFrameLayout(dialog.context)
dialogContentWithBackground.background = decorView.background
// Make the window background transparent. Note that setting the window (or
@@ -720,7 +721,10 @@
// Make the background view invisible until we start the animation. We use the transition
// visibility like GhostView does so that we don't mess up with the accessibility tree (see
- // b/204944038#comment17).
+ // b/204944038#comment17). Given that this background implements LaunchableView, we call
+ // setShouldBlockVisibilityChanges() early so that the current visibility (VISIBLE) is
+ // restored at the end of the animation.
+ dialogContentWithBackground.setShouldBlockVisibilityChanges(true)
dialogContentWithBackground.setTransitionVisibility(View.INVISIBLE)
// Make sure the dialog is visible instantly and does not do any window animation.
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index 26aa0e8..23e3a01 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -34,6 +34,7 @@
import android.view.ViewGroupOverlay
import android.widget.FrameLayout
import com.android.internal.jank.InteractionJankMonitor
+import java.lang.IllegalArgumentException
import java.util.LinkedList
import kotlin.math.min
import kotlin.math.roundToInt
@@ -46,7 +47,8 @@
* of the ghosted view.
*
* Important: [ghostedView] must be attached to a [ViewGroup] when calling this function and during
- * the animation.
+ * the animation. It must also implement [LaunchableView], otherwise an exception will be thrown
+ * during this controller instantiation.
*
* Note: Avoid instantiating this directly and call [ActivityLaunchAnimator.Controller.fromView]
* whenever possible instead.
@@ -101,6 +103,15 @@
private val background: Drawable?
init {
+ // Make sure the View we launch from implements LaunchableView to avoid visibility issues.
+ if (ghostedView !is LaunchableView) {
+ throw IllegalArgumentException(
+ "A GhostedViewLaunchAnimatorController was created from a View that does not " +
+ "implement LaunchableView. This can lead to subtle bugs where the visibility " +
+ "of the View we are launching from is not what we expected."
+ )
+ }
+
/** Find the first view with a background in [view] and its children. */
fun findBackground(view: View): Drawable? {
if (view.background != null) {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableFrameLayout.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableFrameLayout.kt
new file mode 100644
index 0000000..2eb503b
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchableFrameLayout.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.animation
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.FrameLayout
+
+/** A [FrameLayout] that also implements [LaunchableView]. */
+open class LaunchableFrameLayout : FrameLayout, LaunchableView {
+ private val delegate =
+ LaunchableViewDelegate(
+ this,
+ superSetVisibility = { super.setVisibility(it) },
+ )
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ defStyleRes: Int
+ ) : super(context, attrs, defStyleAttr, defStyleRes)
+
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {
+ delegate.setShouldBlockVisibilityChanges(block)
+ }
+
+ override fun setVisibility(visibility: Int) {
+ delegate.setVisibility(visibility)
+ }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
index 9257f99..46d5a5c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
@@ -25,7 +25,7 @@
/** A [DialogLaunchAnimator.Controller] that can animate a [View] from/to a dialog. */
class ViewDialogLaunchAnimatorController
internal constructor(
- internal val source: View,
+ private val source: View,
override val cuj: DialogCuj?,
) : DialogLaunchAnimator.Controller {
override val viewRoot: ViewRootImpl?
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
index 4e96dda..cfc38df 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt
@@ -33,8 +33,8 @@
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.LocalMinimumTouchTargetEnforcement
import androidx.compose.material3.contentColorFor
+import androidx.compose.material3.minimumInteractiveComponentSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
@@ -65,21 +65,17 @@
import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.layout.boundsInRoot
import androidx.compose.ui.layout.findRootCoordinates
-import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewTreeLifecycleOwner
import androidx.lifecycle.ViewTreeViewModelStoreOwner
-import com.android.compose.runtime.movableContentOf
import com.android.systemui.animation.Expandable
import com.android.systemui.animation.LaunchAnimator
import kotlin.math.max
import kotlin.math.min
-import kotlin.math.roundToInt
/**
* Create an expandable shape that can launch into an Activity or a Dialog.
@@ -220,21 +216,8 @@
// If this expandable is expanded when it's being directly clicked on, let's ensure that it has
// the minimum interactive size followed by all M3 components (48.dp).
val minInteractiveSizeModifier =
- if (onClick != null && LocalMinimumTouchTargetEnforcement.current) {
- // TODO(b/242040009): Replace this by Modifier.minimumInteractiveComponentSize() once
- // http://aosp/2305511 is available.
- val minTouchSize = LocalViewConfiguration.current.minimumTouchTargetSize
- Modifier.layout { measurable, constraints ->
- // Copied from androidx.compose.material3.InteractiveComponentSize.kt
- val placeable = measurable.measure(constraints)
- val width = maxOf(placeable.width, minTouchSize.width.roundToPx())
- val height = maxOf(placeable.height, minTouchSize.height.roundToPx())
- layout(width, height) {
- val centerX = ((width - placeable.width) / 2f).roundToInt()
- val centerY = ((height - placeable.height) / 2f).roundToInt()
- placeable.place(centerX, centerY)
- }
- }
+ if (onClick != null) {
+ Modifier.minimumInteractiveComponentSize()
} else {
Modifier
}
diff --git a/packages/SystemUI/docs/device-entry/quickaffordance.md b/packages/SystemUI/docs/device-entry/quickaffordance.md
index ccb35fa..79d5718 100644
--- a/packages/SystemUI/docs/device-entry/quickaffordance.md
+++ b/packages/SystemUI/docs/device-entry/quickaffordance.md
@@ -52,6 +52,10 @@
* Unselect an already-selected quick affordance from a slot
* Unselect all already-selected quick affordances from a slot
+## Testing
+* Add a unit test for your implementation of `KeyguardQuickAffordanceConfig`
+* Manually verify that your implementation works in multi-user environments from both the main user and a secondary user
+
## Debugging
To see the current state of the system, you can run `dumpsys`:
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index bc6e5ec..e0cc8f4 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -50,16 +50,24 @@
String TAG = "BcSmartspaceDataPlugin";
/** Register a listener to get Smartspace data. */
- void registerListener(SmartspaceTargetListener listener);
+ default void registerListener(SmartspaceTargetListener listener) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/** Unregister a listener. */
- void unregisterListener(SmartspaceTargetListener listener);
+ default void unregisterListener(SmartspaceTargetListener listener) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/** Register a SmartspaceEventNotifier. */
- default void registerSmartspaceEventNotifier(SmartspaceEventNotifier notifier) {}
+ default void registerSmartspaceEventNotifier(SmartspaceEventNotifier notifier) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/** Push a SmartspaceTargetEvent to the SmartspaceEventNotifier. */
- default void notifySmartspaceEvent(SmartspaceTargetEvent event) {}
+ default void notifySmartspaceEvent(SmartspaceTargetEvent event) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/** Allows for notifying the SmartspaceSession of SmartspaceTargetEvents. */
interface SmartspaceEventNotifier {
@@ -72,16 +80,20 @@
* will be responsible for correctly setting the LayoutParams
*/
default SmartspaceView getView(ViewGroup parent) {
- return null;
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
}
/**
* As the smartspace view becomes available, allow listeners to receive an event.
*/
- default void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) { }
+ default void addOnAttachStateChangeListener(View.OnAttachStateChangeListener listener) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/** Updates Smartspace data and propagates it to any listeners. */
- void onTargetsAvailable(List<SmartspaceTarget> targets);
+ default void onTargetsAvailable(List<SmartspaceTarget> targets) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/** Provides Smartspace data to registered listeners. */
interface SmartspaceTargetListener {
@@ -96,7 +108,9 @@
/**
* Sets {@link BcSmartspaceConfigPlugin}.
*/
- void registerConfigProvider(BcSmartspaceConfigPlugin configProvider);
+ default void registerConfigProvider(BcSmartspaceConfigPlugin configProvider) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/**
* Primary color for unprotected text
@@ -138,28 +152,38 @@
/**
* Set or clear Do Not Disturb information.
*/
- void setDnd(@Nullable Drawable image, @Nullable String description);
+ default void setDnd(@Nullable Drawable image, @Nullable String description) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/**
* Set or clear next alarm information
*/
- void setNextAlarm(@Nullable Drawable image, @Nullable String description);
+ default void setNextAlarm(@Nullable Drawable image, @Nullable String description) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/**
* Set or clear device media playing
*/
- void setMediaTarget(@Nullable SmartspaceTarget target);
+ default void setMediaTarget(@Nullable SmartspaceTarget target) {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/**
* Get the index of the currently selected page.
*/
- int getSelectedPage();
+ default int getSelectedPage() {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
/**
* Return the top padding value from the currently visible card, or 0 if there is no current
* card.
*/
- int getCurrentCardTopPadding();
+ default int getCurrentCardTopPadding() {
+ throw new UnsupportedOperationException("Not implemented by " + getClass());
+ }
}
/** Interface for launching Intents, which can differ on the lockscreen */
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
index 9ed3bac..70b5d73 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -105,6 +105,11 @@
default void onDozingChanged(boolean isDozing) {}
/**
+ * Callback to be notified when Dreaming changes. Dreaming is stored separately from state.
+ */
+ default void onDreamingChanged(boolean isDreaming) {}
+
+ /**
* Callback to be notified when the doze amount changes. Useful for animations.
* Note: this will be called for each animation frame. Please be careful to avoid
* performance regressions.
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 2cac9c7..90851e2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -45,7 +45,7 @@
android:id="@+id/user_switcher_header"
android:textDirection="locale"
android:layout_width="@dimen/bouncer_user_switcher_width"
- android:layout_height="wrap_content" />
+ android:layout_height="match_parent" />
</com.android.keyguard.KeyguardUserSwitcherAnchor>
</LinearLayout>
diff --git a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
index a1068c6..6c8db91 100644
--- a/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw600dp/dimens.xml
@@ -25,9 +25,6 @@
<!-- Margin around the various security views -->
<dimen name="keyguard_security_view_top_margin">12dp</dimen>
- <!-- Padding for the lock icon on the keyguard -->
- <dimen name="lock_icon_padding">16dp</dimen>
-
<!-- Overload default clock widget parameters -->
<dimen name="widget_big_font_size">100dp</dimen>
<dimen name="widget_label_font_size">18sp</dimen>
diff --git a/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml
new file mode 100644
index 0000000..3807b92
--- /dev/null
+++ b/packages/SystemUI/res/drawable/keyguard_settings_popup_menu_background.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+<ripple
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/white"/>
+ <corners android:radius="28dp" />
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners android:radius="28dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml b/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml
deleted file mode 100644
index 1a1fc75..0000000
--- a/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml
+++ /dev/null
@@ -1,160 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<com.android.systemui.screenshot.DraggableConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/clipboard_ui"
- android:theme="@style/FloatingOverlay"
- android:alpha="0"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:contentDescription="@string/clipboard_overlay_window_name">
- <ImageView
- android:id="@+id/actions_container_background"
- android:visibility="gone"
- android:layout_height="0dp"
- android:layout_width="0dp"
- android:elevation="4dp"
- android:background="@drawable/action_chip_container_background"
- android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
- app:layout_constraintBottom_toBottomOf="@+id/actions_container"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="@+id/actions_container"
- app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
- <HorizontalScrollView
- android:id="@+id/actions_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
- android:paddingEnd="@dimen/overlay_action_container_padding_right"
- android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
- android:elevation="4dp"
- android:scrollbars="none"
- android:layout_marginBottom="4dp"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintWidth_percent="1.0"
- app:layout_constraintWidth_max="wrap"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@+id/preview_border"
- app:layout_constraintEnd_toEndOf="parent">
- <LinearLayout
- android:id="@+id/actions"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:animateLayoutChanges="true">
- <include layout="@layout/overlay_action_chip"
- android:id="@+id/share_chip"/>
- <include layout="@layout/overlay_action_chip"
- android:id="@+id/remote_copy_chip"/>
- <include layout="@layout/overlay_action_chip"
- android:id="@+id/edit_chip"/>
- </LinearLayout>
- </HorizontalScrollView>
- <View
- android:id="@+id/preview_border"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_marginStart="@dimen/overlay_offset_x"
- android:layout_marginBottom="12dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- android:elevation="7dp"
- app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
- app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
- android:background="@drawable/overlay_border"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/clipboard_preview_end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierMargin="@dimen/overlay_border_width"
- app:barrierDirection="end"
- app:constraint_referenced_ids="clipboard_preview"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/clipboard_preview_top"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierDirection="top"
- app:barrierMargin="@dimen/overlay_border_width_neg"
- app:constraint_referenced_ids="clipboard_preview"/>
- <FrameLayout
- android:id="@+id/clipboard_preview"
- android:elevation="7dp"
- android:background="@drawable/overlay_preview_background"
- android:clipChildren="true"
- android:clipToOutline="true"
- android:clipToPadding="true"
- android:layout_width="@dimen/clipboard_preview_size"
- android:layout_margin="@dimen/overlay_border_width"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- app:layout_constraintBottom_toBottomOf="@id/preview_border"
- app:layout_constraintStart_toStartOf="@id/preview_border"
- app:layout_constraintEnd_toEndOf="@id/preview_border"
- app:layout_constraintTop_toTopOf="@id/preview_border">
- <TextView android:id="@+id/text_preview"
- android:textFontWeight="500"
- android:padding="8dp"
- android:gravity="center|start"
- android:ellipsize="end"
- android:autoSizeTextType="uniform"
- android:autoSizeMinTextSize="@dimen/clipboard_overlay_min_font"
- android:autoSizeMaxTextSize="@dimen/clipboard_overlay_max_font"
- android:textColor="?attr/overlayButtonTextColor"
- android:textColorLink="?attr/overlayButtonTextColor"
- android:background="?androidprv:attr/colorAccentSecondary"
- android:layout_width="@dimen/clipboard_preview_size"
- android:layout_height="@dimen/clipboard_preview_size"/>
- <ImageView
- android:id="@+id/image_preview"
- android:scaleType="fitCenter"
- android:adjustViewBounds="true"
- android:contentDescription="@string/clipboard_image_preview"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- <TextView
- android:id="@+id/hidden_preview"
- android:visibility="gone"
- android:textFontWeight="500"
- android:padding="8dp"
- android:gravity="center"
- android:textSize="14sp"
- android:textColor="?attr/overlayButtonTextColor"
- android:background="?androidprv:attr/colorAccentSecondary"
- android:layout_width="@dimen/clipboard_preview_size"
- android:layout_height="@dimen/clipboard_preview_size"/>
- </FrameLayout>
- <FrameLayout
- android:id="@+id/dismiss_button"
- android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
- android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
- android:elevation="10dp"
- android:visibility="gone"
- android:alpha="0"
- app:layout_constraintStart_toEndOf="@id/clipboard_preview"
- app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
- app:layout_constraintTop_toTopOf="@id/clipboard_preview"
- app:layout_constraintBottom_toTopOf="@id/clipboard_preview"
- android:contentDescription="@string/clipboard_dismiss_description">
- <ImageView
- android:id="@+id/dismiss_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_margin="@dimen/overlay_dismiss_button_margin"
- android:src="@drawable/overlay_cancel"/>
- </FrameLayout>
-</com.android.systemui.screenshot.DraggableConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
index de96e97..446bb01 100644
--- a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:paddingVertical="@dimen/dream_overlay_complication_home_controls_padding">
- <ImageView
+ <com.android.systemui.common.ui.view.LaunchableImageView
android:id="@+id/home_controls_chip"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
android:layout_width="@dimen/keyguard_affordance_fixed_width"
diff --git a/packages/SystemUI/res/layout/global_actions_grid_lite.xml b/packages/SystemUI/res/layout/global_actions_grid_lite.xml
index 5588fd3..a64c9ae 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_lite.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_lite.xml
@@ -33,7 +33,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_weight="1">
- <androidx.constraintlayout.widget.ConstraintLayout
+ <com.android.systemui.common.ui.view.LaunchableConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@android:id/list"
@@ -55,6 +55,6 @@
app:flow_horizontalGap="@dimen/global_actions_lite_padding"
app:flow_verticalGap="@dimen/global_actions_lite_padding"
app:flow_horizontalStyle="packed"/>
- </androidx.constraintlayout.widget.ConstraintLayout>
+ </com.android.systemui.common.ui.view.LaunchableConstraintLayout>
</com.android.systemui.globalactions.GlobalActionsLayoutLite>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
index 6f33623..07c428b 100644
--- a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
+++ b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml
@@ -24,7 +24,7 @@
android:layout_gravity="end">
<!-- We add a background behind the UserAvatarView with the same color and with a circular shape
so that this view can be expanded into a Dialog or an Activity. -->
- <FrameLayout
+ <com.android.systemui.animation.LaunchableFrameLayout
android:id="@+id/kg_multi_user_avatar_with_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -42,5 +42,5 @@
systemui:framePadding="0dp"
systemui:frameWidth="0dp">
</com.android.systemui.statusbar.phone.UserAvatarView>
- </FrameLayout>
+ </com.android.systemui.animation.LaunchableFrameLayout>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml
new file mode 100644
index 0000000..89d88fe
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_settings_popup_menu.xml
@@ -0,0 +1,50 @@
+<?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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="52dp"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:background="@drawable/keyguard_settings_popup_menu_background"
+ android:paddingStart="16dp"
+ android:paddingEnd="24dp"
+ android:paddingVertical="16dp">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="20dp"
+ android:layout_height="20dp"
+ android:layout_marginEnd="16dp"
+ android:tint="?android:attr/textColorPrimary"
+ android:importantForAccessibility="no"
+ tools:ignore="UseAppTint" />
+
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp"
+ android:maxLines="1"
+ android:ellipsize="end" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index abc8337..f2e114b 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -106,7 +106,7 @@
app:layout_constrainedWidth="true"
app:layout_constraintWidth_min="@dimen/min_clickable_item_size"
app:layout_constraintHeight_min="@dimen/min_clickable_item_size">
- <LinearLayout
+ <com.android.systemui.common.ui.view.LaunchableLinearLayout
android:id="@+id/media_seamless_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -135,7 +135,7 @@
android:textDirection="locale"
android:textSize="12sp"
android:lineHeight="16sp" />
- </LinearLayout>
+ </com.android.systemui.common.ui.view.LaunchableLinearLayout>
</LinearLayout>
<!-- Song name -->
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index c949ba0..18d231c 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -23,7 +23,7 @@
android:layout_gravity="center_vertical|start"
android:layout_marginStart="5dp"
>
- <LinearLayout
+ <com.android.systemui.common.ui.view.LaunchableLinearLayout
android:id="@+id/ongoing_call_chip_background"
android:layout_width="wrap_content"
android:layout_height="@dimen/ongoing_appops_chip_height"
@@ -55,5 +55,5 @@
android:textColor="?android:attr/colorPrimary"
/>
- </LinearLayout>
+ </com.android.systemui.common.ui.view.LaunchableLinearLayout>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index 496eb6e..7e8bc2c 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -31,7 +31,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/actions_container"
app:layout_constraintEnd_toEndOf="@+id/actions_container"
- app:layout_constraintBottom_toTopOf="@id/screenshot_message_container"/>
+ app:layout_constraintBottom_toTopOf="@id/guideline"/>
<HorizontalScrollView
android:id="@+id/actions_container"
android:layout_width="0dp"
@@ -127,57 +127,28 @@
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
android:elevation="7dp"/>
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/guideline"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_end="0dp" />
+
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/screenshot_message_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/overlay_action_container_margin_horizontal"
- android:layout_marginVertical="4dp"
+ android:layout_marginTop="4dp"
+ android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom"
android:paddingHorizontal="@dimen/overlay_action_container_padding_end"
android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
android:elevation="4dp"
android:background="@drawable/action_chip_container_background"
- android:visibility="gone"
+ android:visibility="invisible"
+ app:layout_constraintTop_toBottomOf="@id/guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent">
-
- <ImageView
- android:id="@+id/screenshot_message_icon"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:paddingEnd="4dp"
- android:src="@drawable/ic_work_app_badge"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/screenshot_message_content"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"/>
-
- <TextView
- android:id="@+id/screenshot_message_content"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@id/screenshot_message_icon"
- app:layout_constraintEnd_toStartOf="@id/message_dismiss_button"/>
-
- <FrameLayout
- android:id="@+id/message_dismiss_button"
- android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
- android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
- app:layout_constraintStart_toEndOf="@id/screenshot_message_content"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
- android:contentDescription="@string/screenshot_dismiss_work_profile">
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_margin="@dimen/overlay_dismiss_button_margin"
- android:src="@drawable/overlay_cancel"/>
- </FrameLayout>
-
+ >
</androidx.constraintlayout.widget.ConstraintLayout>
</com.android.systemui.screenshot.DraggableConstraintLayout>
diff --git a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
new file mode 100644
index 0000000..c794d91
--- /dev/null
+++ b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <ImageView
+ android:id="@+id/screenshot_message_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:paddingEnd="4dp"
+ android:src="@drawable/ic_work_app_badge"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/screenshot_message_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"/>
+
+ <TextView
+ android:id="@+id/screenshot_message_content"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@id/screenshot_message_icon"
+ app:layout_constraintEnd_toStartOf="@id/message_dismiss_button"/>
+
+ <FrameLayout
+ android:id="@+id/message_dismiss_button"
+ android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
+ android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
+ app:layout_constraintStart_toEndOf="@id/screenshot_message_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:contentDescription="@string/screenshot_dismiss_work_profile">
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/overlay_dismiss_button_margin"
+ android:src="@drawable/overlay_cancel"/>
+ </FrameLayout>
+</merge>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 159323a..3c860a9 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -26,6 +26,11 @@
android:layout_height="match_parent"
android:background="@android:color/transparent">
+ <com.android.systemui.common.ui.view.LongPressHandlingView
+ android:id="@+id/keyguard_long_press"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
<ViewStub
android:id="@+id/keyguard_qs_user_switch_stub"
android:layout="@layout/keyguard_qs_user_switch"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 771f972..d196110 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Outomaties"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Geen klank of vibrasie nie"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Geen klank of vibrasie nie en verskyn laer in gespreksafdeling"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Kan lui of vibreer op grond van toestelinstellings"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Kan lui of vibreer op grond van toestelinstellings. Gesprekke van <xliff:g id="APP_NAME">%1$s</xliff:g> af verskyn by verstek in ’n borrel."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Laat die stelsel bepaal of hierdie kennisgewing \'n klank moet maak of vibreer"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Bevorder na Verstek"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Gedegradeer na Stil"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Kies program om kontroles by te voeg"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrole bygevoeg.}other{# kontroles bygevoeg.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Verwyder"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"As gunsteling gemerk"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"As gunsteling gemerk; posisie <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"As gunsteling ontmerk"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer weer"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Voeg kontroles by"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Wysig kontroles"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Voeg uitvoere by"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groep"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 toestel gekies"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batterykrag oor"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koppel jou stilus aan ’n laaier"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stilus se battery is amper pap"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Kan nie van hierdie profiel af bel nie"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Jou werkbeleid laat jou toe om slegs van die werkprofiel af foonoproepe te maak"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skakel oor na werkprofiel"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Maak toe"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 447f98d..bf00ec3 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ራስ-ሰር"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ምንም ድምፅ ወይም ንዝረት የለም"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ምንም ድምፅ ወይም ንዝረት የለም እና በውይይት ክፍል ላይ አይታይም"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"በመሣሪያ ቅንብሮች መሰረት ሊጮህ ወይም ሊነዝር ይችላል"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"በስልክ ቅንብሮች መሰረት ሊጮህ ወይም ሊነዝር ይችላል። የ<xliff:g id="APP_NAME">%1$s</xliff:g> ውይይቶች በነባሪነት አረፋ ይሆናሉ።"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ይህ ማሳወቂያ ድምፅ ወይም ንዝረት መደረግ ካለበት ስርዓቱ እንዲወሰን ያድርጉት"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ሁኔታ:</b> ለነባሪ ከፍ ተዋውቋል።"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ሁኔታ:</b> ወደ ዝምታ ዝቅ ተደርጓል"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"መቆጣጠሪያዎችን ለማከል መተግበሪያ ይምረጡ"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ቁጥጥር ታክሏል።}one{# ቁጥጥር ታክሏል።}other{# ቁጥጥሮች ታክለዋል።}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ተወግዷል"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ተወዳጅ የተደረገ"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"ተወዳጅ ተደርጓል፣ አቋም <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ተወዳጅ አልተደረገም"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"ስህተት፣ እንደገና ይሞክሩ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"መቆጣጠሪያዎችን አክል"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"መቆጣጠሪያዎችን ያርትዑ"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ውጽዓቶችን ያክሉ"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ቡድን"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 መሣሪያ ተመርጧል"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ባትሪ ይቀራል"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ብሮስፌዎን ከኃይል መሙያ ጋር ያገናኙ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"የብሮስፌ ባትሪ ዝቅተኛ ነው"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"የቪድዮ ካሜራ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ከዚህ መገለጫ መደወል አይቻልም"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"የሥራ መመሪያዎ እርስዎ ከሥራ መገለጫው ብቻ ጥሪ እንዲያደርጉ ይፈቅድልዎታል"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ወደ የሥራ መገለጫ ቀይር"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"ዝጋ"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 8099b23..804e565 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"تلقائي"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صوت أو اهتزاز"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صوت أو اهتزاز وتظهر في أسفل قسم المحادثات"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الجهاز"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الجهاز. تظهر المحادثات من \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" كفقاعات تلقائيًا."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"السماح للنظام بتحديد ما إذا يجب اهتزاز الجهاز أو إصدار رنين عند تلقّي هذا الإشعار"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>الحالة:</b> تمت الترقية إلى الإعداد التلقائي"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>الحالة:</b> تم خفض الترتيب إلى الوضع صامت"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"اختيار تطبيق لإضافة عناصر التحكّم"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{تمت إضافة عنصر تحكّم واحد.}zero{تمت إضافة # عنصر تحكّم.}two{تمت إضافة عنصرَي تحكّم.}few{تمت إضافة # عناصر تحكّم.}many{تمت إضافة # عنصر تحكّم.}other{تمت إضافة # عنصر تحكّم.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"تمت الإزالة"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"تمت الإضافة إلى المفضّلة"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"تمت الإضافة إلى المفضّلة، الموضع <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"تمت الإزالة من المفضّلة"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"حدث خطأ، يُرجى إعادة المحاولة."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"إضافة عناصر تحكّم"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"تعديل عناصر التحكّم"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"إضافة مخرجات"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"مجموعة"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"تم اختيار جهاز واحد."</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"النسبة المئوية المتبقية من شحن البطارية: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"عليك توصيل قلم الشاشة بشاحن."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"بطارية قلم الشاشة منخفضة"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"كاميرا فيديو"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"لا يمكن الاتصال باستخدام هذا الملف الشخصي."</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"تسمح لك سياسة العمل بإجراء المكالمات الهاتفية من الملف الشخصي للعمل فقط."</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"التبديل إلى الملف الشخصي للعمل"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"إغلاق"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index fa04cb8..9e08a81 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"স্বয়ংক্ৰিয়"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"কোনো ধ্বনি অথবা কম্পন নাই"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"কোনো ধ্বনি অথবা কম্পন নাই আৰু বাৰ্তালাপ শাখাটোৰ তলৰ অংশত দেখা পোৱা যায়"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ডিভাইচৰ ছেটিঙৰ ওপৰত নিৰ্ভৰ কৰি ৰিং কৰিব অথবা কম্পন হ’ব পাৰে"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ডিভাইচৰ ছেটিঙৰ ওপৰত নিৰ্ভৰ কৰি ৰিং কৰিব অথবা কম্পন হ’ব পাৰে। <xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাৰ্তালাপ ডিফ’ল্টভাৱে বাবল হিচাপে প্ৰদৰ্শিত হয়।"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"এই জাননীটোৱে ধ্বনি নে কম্পন সৃষ্টি কৰিব সেয়া ছিষ্টেমটোক নিৰ্ধাৰণ কৰিবলৈ দিয়ক"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>স্থিতি:</b> ডিফ’ল্টলৈ বৃদ্ধি কৰা হৈছে"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>স্থিতি:</b> নীৰৱলৈ হ্ৰাস কৰা হৈছে"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"নিয়ন্ত্ৰণসমূহ যোগ কৰিবলৈ এপ্ বাছনি কৰক"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}one{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}other{# টা নিয়ন্ত্ৰণ যোগ দিয়া হৈছে।}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"আঁতৰোৱা হ’ল"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"প্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"প্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল, স্থান <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"অপ্ৰিয় হিচাপে চিহ্নিত কৰা হ’ল"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"আসোঁৱাহ হৈছে, আকৌ চেষ্টা কৰক"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"নিয়ন্ত্ৰণসমূহ যোগ দিয়ক"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"নিয়ন্ত্ৰণসমূহ সম্পাদনা কৰক"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"আউটপুটসমূহ যোগ দিয়ক"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"গোট"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"১ টা ডিভাইচ বাছনি কৰা হৈছে"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> বেটাৰী বাকী আছে"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"আপোনাৰ ষ্টাইলাছ এটা চাৰ্জাৰৰ সৈতে সংযোগ কৰক"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ষ্টাইলাছৰ বেটাৰী কম আছে"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"ভিডিঅ’ কেমেৰা"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"এই প্ৰ’ফাইলৰ পৰা কল কৰিব নোৱাৰি"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"আপোনাৰ কৰ্মস্থানৰ নীতিয়ে আপোনাক কেৱল কৰ্মস্থানৰ প্ৰ’ফাইলৰ পৰা ফ’ন কল কৰিবলৈ দিয়ে"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"কৰ্মস্থানৰ প্ৰ’ফাইললৈ সলনি কৰক"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"বন্ধ কৰক"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index e6b27e0..3f2f453 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Səs və ya vibrasiya yoxdur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Söhbət siyahısının aşağısında səssiz və vibrasiyasız görünür"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Cihaz ayarlarına əsasən zəng çala və ya vibrasiya edə bilər"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Cihaz ayarlarına əsasən zəng çala və ya vibrasiya edə bilər. <xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqindən söhbətlərdə defolt olaraq qabarcıq çıxır."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Bu bildirişin səs çıxarması və ya vibrasiya etməsi sistem tərəfindən təyin edilsin"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Defolt ayara keçirilib"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Səssiz rejimə keçirilib"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Kontrol əlavə etmək üçün tətbiq seçin"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# nizamlayıcı əlavə edilib.}other{# nizamlayıcı əlavə edilib.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Silinib"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Sevimlilərə əlavə edilib"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Sevimlilərə əlavə edilib, sıra: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Sevimlilərdən silinib"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Xəta, yenidən cəhd edin"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Vidcet əlavə edin"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Vidcetlərə düzəliş edin"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Nəticələri əlavə edin"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Qrup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçilib"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> enerji qalıb"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Qələmi adapterə qoşun"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Qələm enerjisi azdır"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Bu profildən zəng etmək mümkün deyil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"İş siyasətiniz yalnız iş profilindən telefon zəngləri etməyə imkan verir"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"İş profilinə keçin"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Bağlayın"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index fb95a91..28f8f11 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatska"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka i vibriranja"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka i vibriranja i prikazuje se u nastavku odeljka za konverzacije"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Može da zvoni ili vibrira u zavisnosti od podešavanja uređaja"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Može da zvoni ili vibrira u zavisnosti od podešavanja uređaja. Konverzacije iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> podrazumevano se prikazuju u oblačićima."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Neka sistem utvrdi da li ovo obaveštenje treba da emituje zvuk ili da vibrira"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Unapređeno u Podrazumevano"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Degradirano u Nečujno"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju za dodavanje kontrola"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrola je dodata.}one{# kontrola je dodata.}few{# kontrole su dodate.}other{# kontrola je dodato.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Označeno je kao omiljeno"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Označeno je kao omiljeno, <xliff:g id="NUMBER">%d</xliff:g>. pozicija"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Uklonjeno je iz omiljenih"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Greška. Probajte ponovo"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Izmeni kontrole"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodajte izlaze"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izabran je 1 uređaj"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo je još<xliff:g id="PERCENTAGE">%s</xliff:g> baterije"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisaljku sa punjačem"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Nizak nivo baterije pisaljke"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Video kamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Ne možete da upućujete pozive sa ovog profila"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Smernice za posao vam omogućavaju da telefonirate samo sa poslovnog profila"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pređi na poslovni profil"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index f1d174d..ec18029 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Аўтаматычна"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без гуку ці вібрацыі"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Паказваецца без гуку ці вібрацыі ў раздзеле размоў"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"У залежнасці ад налад прылады магчымы званок або вібрацыя"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"У залежнасці ад налад прылады магчымы званок або вібрацыя. Размовы ў праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" стандартна паяўляюцца ў выглядзе ўсплывальных апавяшчэнняў."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Сістэма сама будзе вызначаць, ці трэба для гэтага апавяшчэння ўключаць гук або вібрацыю"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Стан:</b> Пазначана як стандартнае"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Стан:</b> Пераведзена ў рэжым \"Без гуку\""</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Выберыце праграму для дадавання элементаў кіравання"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Дададзены # элемент кіравання.}one{Дададзена # элемента кіравання.}few{Дададзена # элементы кіравання.}many{Дададзена # элементаў кіравання.}other{Дададзена # элемента кіравання.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Выдалена"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Дададзена ў абранае"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Дададзена ў абранае, пазіцыя <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Выдалена з абранага"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Памылка, паўтарыце спробу"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Дадаць элементы кіравання"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Змяніць элементы кіравання"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Дадайце прылады вываду"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрана 1 прылада"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Засталося зараду: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Падключыце пяро да зараднай прылады"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Нізкі ўзровень зараду пяра"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Відэакамера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Не ўдалося зрабіць выклік з гэтага профілю"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Згодна з палітыкай вашай арганізацыі, рабіць тэлефонныя выклікі дазволена толькі з працоўнага профілю"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Пераключыцца на працоўны профіль"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыць"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index ce4b9ed..72c6b9d 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибриране"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибриране и се показва по-долу в секцията с разговори"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да звъни или да вибрира въз основа на настройките на устройството"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да звъни или да вибрира въз основа на настройките на устройството. Разговорите от <xliff:g id="APP_NAME">%1$s</xliff:g> се показват като балончета по подразбиране."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Нека системата да определя дали дадено известие да се придружава от звук, или вибриране"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Състояние:</b> Повишено до основно"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Състояние:</b> Понижено до беззвучно"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Изберете приложение, за да добавите контроли"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Добавена е # контрола.}other{Добавени са # контроли.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Премахнато"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Означено като любимо"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Означено като любимо – позиция <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Не е означено като любимо"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Грешка. Опитайте отново"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Добавяне на контроли"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Редактиране на контролите"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Добавяне на изходящи устройства"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 избрано устройство"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Оставаща батерия: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Свържете писалката към зарядно устройство"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Батерията на писалката е изтощена"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Не може да се извърши обаждане от този потребителски профил"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Служебните правила ви дават възможност да извършвате телефонни обаждания само от служебния потребителски профил"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Превключване към служебния потребителски профил"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затваряне"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 33e8eef..598db2c 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"অটোমেটিক"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"আওয়াজ করবে না বা ভাইব্রেট হবে না"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"আওয়াজ করবে না বা ভাইব্রেট হবে না এবং কথোপকথন বিভাগের নিচের দিকে দেখা যাবে"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ডিভাইসের সেটিংস অনুযায়ী রিং বা ভাইব্রেট হতে পারে"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ডিভাইসের সেটিংস অনুযায়ী রিং বা ভাইব্রেট হতে পারে। <xliff:g id="APP_NAME">%1$s</xliff:g>-এর কথোপকথন সাধারণত বাবলের মতো দেখাবে।"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"এই বিজ্ঞপ্তি এলে ডিভাইস আওয়াজ করবে না ভাইব্রেট করবে তা সিস্টেমকে সেট করতে দিন"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>স্ট্যাটাস:</b> লেভেল বাড়িয়ে ডিফল্ট করা হয়েছে"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>স্ট্যাটাস:</b> লেভেল কমিয়ে সাইলেন্ করা হয়েছে"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"কন্ট্রোল যোগ করতে অ্যাপ বেছে নিন"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{#টি কন্ট্রোল যোগ করা হয়েছে।}one{#টি কন্ট্রোল যোগ করা হয়েছে।}other{#টি কন্ট্রোল যোগ করা হয়েছে।}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"সরানো হয়েছে"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"পছন্দসই হিসেবে চিহ্নিত করেছেন"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"পছন্দসই হিসেবে চিহ্নিত করেছেন, অবস্থান <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"পছন্দসই থেকে সরিয়ে দিয়েছেন"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"সমস্যা হয়েছে, আবার চেষ্টা করুন"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"কন্ট্রোল যোগ করুন"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"কন্ট্রোল এডিট করুন"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"আউটপুট যোগ করুন"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"গ্রুপ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"১টি ডিভাইস বেছে নেওয়া হয়েছে"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ব্যাটারির চার্জ বাকি আছে"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"কোনও চার্জারের সাথে আপনার স্টাইলাস কানেক্ট করুন"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"স্টাইলাস ব্যাটারিতে চার্জ কম আছে"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"ভিডিও ক্যামেরা"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"এই প্রোফাইল থেকে কল করা যাচ্ছে না"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"কাজ সংক্রান্ত নীতি, আপনাকে শুধুমাত্র অফিস প্রোফাইল থেকে কল করার অনুমতি দেয়"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"অফিস প্রোফাইলে পাল্টে নিন"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"বন্ধ করুন"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c0c609d..66ead20 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -532,8 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka ili vibracije"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka ili vibracije i pojavljuje se pri dnu odjeljka razgovora"</string>
- <string name="notification_channel_summary_default" msgid="777294388712200605">"Možda će zvoniti ili vibrirati, ovisno o postavkama uređaja"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Možda će zvoniti ili vibrirati, ovisno o postavkama uređaja. Razgovori iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazuju se u oblačiću prema zadanim postavkama."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Može zvoniti ili vibrirati na osnovu postavki uređaja"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Može zvoniti ili vibrirati na osnovu postavki uređaja. Razgovori iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazuju se u oblačićima prema zadanim postavkama."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Neka sistem odluči treba li se ovo obavještenje oglasiti zvukom ili vibracijom"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> je unaprijeđen u Zadano"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> je unazađen u Nečujno"</string>
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju da dodate kontrole"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodana je # kontrola.}one{Dodana je # kontrola.}few{Dodane su # kontrole.}other{Dodano je # kontrola.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite li dodati aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Kada dodate aplikaciju <xliff:g id="APPNAME">%s</xliff:g>, može dodati kontrole i sadržaj na ovu ploču. U nekim aplikacijama možete odabrati koje se kontrole prikazuju ovdje."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano u omiljeno"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano u omiljeno, pozicija <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Uklonjeno iz omiljenog"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Greška, pokušajte ponovo"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodavanje aplikacije"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodajte izlaze"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je 1 uređaj"</string>
@@ -1021,9 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostalo baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Baterija pisaljke je slaba"</string>
- <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
- <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nije moguće uspostavljati pozive s ovog profila"</string>
- <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaša pravila za poslovne uređaje omogućuju vam upućivanje poziva samo s poslovnog profila"</string>
- <string name="call_from_work_profile_action" msgid="2937701298133010724">"Prijeđite na poslovni profil"</string>
+ <string name="video_camera" msgid="7654002575156149298">"Video kamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nije moguće pozvati s ovog profila"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Radna pravila vam dozvoljavaju upućivanje telefonskih poziva samo s radnog profila"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pređite na radni profil"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 9c10046..953cc35 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automàtic"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sense so ni vibració"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sense so ni vibració i es mostra més avall a la secció de converses"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Pot sonar o vibrar en funció de la configuració del dispositiu"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Pot sonar o vibrar en funció de la configuració del dispositiu. Les converses de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> es mostren com a bombolles de manera predeterminada."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Fes que el sistema determini si aquesta notificació ha d\'emetre un so o una vibració"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estat</b>: s\'ha augmentat a Predeterminat"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estat</b>: s\'ha disminuït a Silenci"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Selecciona l\'aplicació per afegir controls"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S\'ha afegit # control.}many{# controls added.}other{S\'han afegit # controls.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Suprimit"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Afegit als preferits"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Afegit als preferits, posició <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Suprimit dels preferits"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error; torna-ho a provar"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Afegeix controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edita els controls"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Afegeix sortides"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositiu seleccionat"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Queda un <xliff:g id="PERCENTAGE">%s</xliff:g> de bateria"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connecta el llapis òptic a un carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria del llapis òptic baixa"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Càmera de vídeo"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"No es pot trucar des d\'aquest perfil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"La teva política de treball et permet fer trucades només des del perfil de treball"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Canvia al perfil de treball"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tanca"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index db60cfd..b1f4c7c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikaci, pro kterou chcete přidat ovládací prvky"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Byl přidán # ovládací prvek.}few{Byly přidány # ovládací prvky.}many{Bylo přidáno # ovládacího prvku.}other{Bylo přidáno # ovládacích prvků.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Odstraněno"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Přidáno do oblíbených"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Přidáno do oblíbených na pozici <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Odebráno z oblíbených"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Chyba, zkuste to znovu"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Přidat ovládací prvky"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Upravit ovládací prvky"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Přidání výstupů"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Je vybráno 1 zařízení"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaše pracovní zásady vám umožňují telefonovat pouze z pracovního profilu"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Přepnout na pracovní profil"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Zavřít"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 4ad66fa..cd857ba 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibration, og den vises længere nede i samtalesektionen"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Kan ringe eller vibrere baseret på enhedens indstillinger"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Kan ringe eller vibrere baseret på enhedens indstillinger. Samtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som standard i bobler."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Få systemet til at afgøre, om denne notifikation skal vibrere eller afspille en lyd"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Angivet som Standard"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Angivet som Lydløs"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Vælg en app for at tilføje styring"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# styringselement er tilføjet.}one{# styringselement er tilføjet.}other{# styringselementer er tilføjet.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Fjernet"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Angivet som favorit"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Angivet som favorit. Position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Fjernet fra favoritter"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Der opstod en fejl. Prøv igen"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Tilføj styring"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Rediger styring"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Tilføj medieudgange"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Der er valgt 1 enhed"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteri tilbage"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Slut din styluspen til en oplader"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Lavt batteriniveau på styluspen"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Du kan ikke ringe fra denne profil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Din arbejdspolitik tillader kun, at du kan foretage telefonopkald fra arbejdsprofilen"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skift til arbejdsprofil"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Luk"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 86d5d76..2b975bc 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisch"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Kein Ton und keine Vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Kein Ton und keine Vibration, erscheint weiter unten im Bereich „Unterhaltungen“"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Kann je nach Geräteeinstellungen klingeln oder vibrieren"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Kann je nach Geräteeinstellungen klingeln oder vibrieren. Unterhaltungen von <xliff:g id="APP_NAME">%1$s</xliff:g> werden standardmäßig als Bubble angezeigt."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Das System entscheiden lassen, ob bei dieser Benachrichtigung ein Ton oder eine Vibration ausgegeben wird"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status</b>: auf „Standard“ hochgestuft"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status</b>: auf „Lautlos“ herabgestuft"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"App zum Hinzufügen von Steuerelementen auswählen"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# Steuerelement hinzugefügt.}other{# Steuerelemente hinzugefügt.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Entfernt"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Zu Favoriten hinzugefügt"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Zu Favoriten hinzugefügt, Position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Aus Favoriten entfernt"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Fehler – versuch es noch mal"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Steuerelemente hinzufügen"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Steuerelemente bearbeiten"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ausgabegeräte hinzufügen"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ein Gerät ausgewählt"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akku bei <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Schließe deinen Eingabestift an ein Ladegerät an"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stylus-Akkustand niedrig"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Keine Anrufe über dieses Profil möglich"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Gemäß den Arbeitsrichtlinien darfst du nur über dein Arbeitsprofil telefonieren"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Zum Arbeitsprofil wechseln"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Schließen"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index ad66104..7e1ee59 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Αυτόματο"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Χωρίς ήχο ή δόνηση"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Χωρίς ήχο ή δόνηση και εμφανίζεται χαμηλά στην ενότητα συζητήσεων"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων συσκευής"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων συσκευής. Οι συζητήσεις από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εμφανίζονται σε συννεφάκι από προεπιλογή."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Επιτρέψτε στο σύστημα να αποφασίσει αν αυτή η ειδοποίηση θα αναπαράγει έναν ήχο ή θα ενεργοποιήσει τη δόνηση της συσκευής"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Κατάσταση:</b> Προάχθηκε σε Προεπιλογή"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Κατάσταση:</b> Υποβιβάστηκε σε Αθόρυβη"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Επιλογή εφαρμογής για προσθήκη στοιχείων ελέγχου"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Προστέθηκε # στοιχείο ελέγχου.}other{Προστέθηκαν # στοιχεία ελέγχου.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Καταργήθηκε"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Προστέθηκε στα αγαπημένα"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Προστέθηκε στα αγαπημένα, στη θέση <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Αφαιρέθηκε από τα αγαπημένα"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Σφάλμα, προσπαθήστε ξανά."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Προσθήκη στοιχείων ελέγχου"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Επεξεργασία στοιχείων ελέγχου"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Προσθήκη εξόδων"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Ομάδα"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Επιλέχτηκε 1 συσκευή"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Απομένει το <xliff:g id="PERCENTAGE">%s</xliff:g> της μπαταρίας"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Συνδέστε τη γραφίδα σε έναν φορτιστή"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Χαμηλή στάθμη μπαταρίας γραφίδας"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Βιντεοκάμερα"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Δεν είναι δυνατή η κλήση από αυτό το προφίλ"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Η πολιτική εργασίας σάς επιτρέπει να πραγματοποιείτε τηλεφωνικές κλήσεις μόνο από το προφίλ εργασίας σας."</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Εναλλαγή σε προφίλ εργασίας"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Κλείσιμο"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 5a82f79..cc7bbac 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavourited"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3bcb98e..004b13a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Favorited"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavorited"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device selected"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 5a82f79..cc7bbac 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavourited"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 5a82f79..cc7bbac 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Favourited"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favourited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavourited"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"One device selected"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 8641491..3023ae5 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control added.}other{# controls added.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removed"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Add <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"When you add <xliff:g id="APPNAME">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Favorited"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorited, position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Unfavorited"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Add app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Add outputs"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Group"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device selected"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Your work policy allows you to make phone calls only from the work profile"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Switch to work profile"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Close"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2d7954d..cdfd492 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"No suena ni vibra, y aparece en la parte inferior de la sección de conversaciones."</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Puede sonar o vibrar según la configuración del dispositivo"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Puede sonar o vibrar según la configuración del dispositivo. Conversaciones de la burbuja de <xliff:g id="APP_NAME">%1$s</xliff:g> de forma predeterminada."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Dejar que el sistema determine si esta notificación debe emitir un sonido o una vibración"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estado:</b> Se promovió a Predeterminada"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> Descendió de nivel a Silenciada"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Se agregó # control.}many{Se agregaron # controles.}other{Se agregaron # controles.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Quitados"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Está en favoritos"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está en favoritos en la posición <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"No está en favoritos"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error. Vuelve a intentarlo."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Agregar controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Agregar salidas"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Se seleccionó 1 dispositivo"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de batería restante"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu pluma stylus a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"La pluma stylus tiene poca batería"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"No se puede llamar desde este perfil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Tu política del trabajo te permite hacer llamadas telefónicas solo desde el perfil de trabajo"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 9bd4b45..70f8254 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sin sonido ni vibración, y se muestra más abajo en la sección de conversaciones"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Puede sonar o vibrar según los ajustes del dispositivo"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Puede sonar o vibrar según los ajustes del dispositivo. Las conversaciones de <xliff:g id="APP_NAME">%1$s</xliff:g> aparecen como burbujas de forma predeterminada."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Haz que el sistema determine si con esta notificación el dispositivo debe sonar o vibrar"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Estado:</b> cambio a Predeterminado"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Estado:</b> cambio a Silencio"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# control añadido.}many{# controles añadidos.}other{# controles añadidos.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Quitado"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Añadido a favoritos"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Añadido a favoritos (posición <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Quitado de favoritos"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error: Vuelve a intentarlo"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Añadir controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Añadir dispositivos de salida"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo seleccionado"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batería restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu lápiz óptico a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Batería del lápiz óptico baja"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"No se puede llamar desde este perfil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Tu política del trabajo solo te permite hacer llamadas telefónicas desde el perfil de trabajo"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Cambiar al perfil de trabajo"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Cerrar"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index baf8520..225812c 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaatne"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ilma heli ja vibreerimiseta"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ilma heli ja vibreerimiseta, kuvatakse vestluste jaotises allpool"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Võib seadme seadete põhjal heliseda või vibreerida"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Võib seadme seadete põhjal heliseda või vibreerida. Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> vestlused kuvatakse vaikimisi mullis."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Laske süsteemil määrata, kas selle märguande puhul peaks esitama heli või vibreerima"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Olek:</b> määrati prioriteet Vaikimisi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Olek:</b> määrati prioriteet Vaikne"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Valige juhtelementide lisamiseks rakendus"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Lisati # juhtnupp.}other{Lisati # juhtnuppu.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Eemaldatud"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Lisatud lemmikuks"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Lisatud lemmikuks, positsioon <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Eemaldatud lemmikute hulgast"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Ilmnes viga, proovige uuesti"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Lisa juhtelemente"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Muuda juhtelemente"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Väljundite lisamine"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupp"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 seade on valitud"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akutase on <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ühendage elektronpliiats laadijaga"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Elektronpliiatsi akutase on madal"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokaamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Sellelt profiililt ei saa helistada"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Teie töökoha eeskirjad lubavad teil helistada ainult tööprofiililt"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Lülitu tööprofiilile"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sule"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b9018f5..37a66b0 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikoa"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ez du tonurik jotzen edo dar-dar egiten"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ez du tonurik jotzen edo dar-dar egiten, eta elkarrizketen atalaren behealdean agertzen da"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Baliteke tonua jotzea edo dardara egitea, gailuaren ezarpenen arabera"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Baliteke tonua jotzea edo dardara egitea, gailuaren ezarpenen arabera. Modu lehenetsian, <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko elkarrizketak burbuila gisa agertzen dira."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Ezarri sistemak zehaztu dezala jakinarazpen honek soinua edo dardara egin behar duen ala ez"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"Lehenetsi gisa ezarri da <b>egoera:</b>"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"Soinurik gabeko modura aldatu da <b>egoera:</b>"</string>
@@ -802,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Aukeratu aplikazio bat kontrolatzeko aukerak gehitzeko"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Kontrolatzeko # aukera gehitu da.}other{Kontrolatzeko # aukera gehitu dira.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Kenduta"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> gehitu nahi duzu?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> gehitzen duzunean, kontrolatzeko aukerak eta edukia gehi ditzake panelean. Aplikazio batzuetan, hemen zein kontrolatzeko aukera agertzen diren aukera dezakezu."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Gogokoetan dago"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>. gogokoa da"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Ez dago gogokoetan"</string>
@@ -868,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Errorea. Saiatu berriro."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Gehitu aukerak"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editatu aukerak"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Gehitu aplikazio bat"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Gehitu irteerak"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Taldea"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 gailu hautatu da"</string>
@@ -1023,14 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateriaren <xliff:g id="PERCENTAGE">%s</xliff:g> geratzen da"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Konektatu arkatza kargagailu batera"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Arkatzak bateria gutxi du"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Bideokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Ezin duzu deitu profil honetatik"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Deiak laneko profiletik soilik egiteko baimena ematen dizute laneko gidalerroek"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Aldatu laneko profilera"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Itxi"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1acbd5a3..a057ad9 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"انتخاب برنامه برای افزودن کنترلها"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# کنترل اضافه شد.}one{# کنترل اضافه شد.}other{# کنترل اضافه شد.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"حذف شد"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"به موارد دلخواه اضافه شد"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"اضافهشده به موارد دلخواه، جایگاه <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"حذفشده از موارد دلخواه"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"خطا، دوباره امتحان کنید"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"افزودن کنترلها"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ویرایش کنترلها"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"افزودن خروجی"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"گروه"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"۱ دستگاه انتخاب شد"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"خطمشی کاری شما فقط به برقراری تماس ازطریق نمایه کاری اجازه میدهد"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"رفتن به نمایه کاری"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"بستن"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index ffea882..c4f5571 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automaattinen"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ei ääntä tai värinää"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ei ääntä tai värinää ja näkyy alempana keskusteluosiossa"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Voi soida tai väristä laitteen asetuksista riippuen"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Voi soida tai väristä laitteen asetuksista riippuen. Keskusteluista (<xliff:g id="APP_NAME">%1$s</xliff:g>) luodaan oletuksena kuplia."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Järjestelmä valitsee, kuuluuko tästä ilmoituksesta ääntä tai väriseekö se"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Tila:</b> valittu oletusarvoiseksi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Tila:</b> hiljennetty"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Valitse sovellus lisätäksesi säätimiä"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# säädin lisätty.}other{# säädintä lisätty.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Poistettu"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Lisätty suosikkeihin"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Lisätty suosikkeihin sijalle <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Poistettu suosikeista"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Virhe, yritä uudelleen"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Lisää säätimiä"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Muokkaa säätimiä"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Lisää toistotapoja"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Ryhmä"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 laite valittu"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akkua jäljellä <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Yhdistä näyttökynä laturiin"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Näyttökynän akku vähissä"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Tästä profiilista ei voi soittaa"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Työkäytäntö sallii sinun soittaa puheluita vain työprofiilista"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Vaihda työprofiiliin"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Sulje"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 0d2db40..a65d2f3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Aucun son ni vibration"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Aucun son ni vibration, et s\'affiche plus bas dans la section des conversations"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Peut sonner ou vibrer, selon les paramètres de l\'appareil"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Peut sonner ou vibrer, selon les paramètres de l\'appareil. Conversations des bulles de <xliff:g id="APP_NAME">%1$s</xliff:g> par défaut."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faire en sorte que le système détermine si cette notification devrait émettre un son ou vibrer"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>État :</b> élevé à la catégorie Par défaut"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>État :</b> abaissé à la catégorie Silencieux"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# de commandes ajoutées.}other{# commandes ajoutées.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Supprimé des favoris"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ajouter des sorties"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Un appareil sélectionné"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Charge restante de la pile : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Pile du stylet faible"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Mode vidéo"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Impossible de passer un appel à partir de ce profil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Votre politique de l\'entreprise vous autorise à passer des appels téléphoniques uniquement à partir de votre profil professionnel"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index e0ee5c4..a01f0c7 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatique"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ni son, ni vibreur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ni son, ni vibreur ; s\'affiche plus bas dans la section des conversations"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Peut sonner ou vibrer en fonction des paramètres de l\'appareil"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Peut sonner ou vibrer en fonction des paramètres de l\'appareil. Les conversations provenant de <xliff:g id="APP_NAME">%1$s</xliff:g> s\'affichent sous forme de bulles par défaut."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Laisser le système déterminer si cette notification doit être accompagnée d\'un son ou d\'une vibration"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>État :</b> Élevée à la catégorie \"Par défaut\""</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>État :</b> Abaissée à la catégorie \"Silencieux\""</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# commande ajoutée.}one{# commande ajoutée.}many{# commandes ajoutées.}other{# commandes ajoutées.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Supprimé"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Ajouté aux favoris"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ajouté aux favoris, en position <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Supprimé des favoris"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ajouter des sorties"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groupe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 appareil sélectionné"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> de batterie restante"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"La batterie du stylet est faible"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Caméra vidéo"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Impossible d\'appeler depuis ce profil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Votre règle professionnelle ne vous permet de passer des appels que depuis le profil professionnel"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Passer au profil professionnel"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fermer"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 87b0178..96416d5 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -802,6 +802,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Escolle unha aplicación para engadir controis"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Engadiuse # control.}other{Engadíronse # controis.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Quitouse"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Está entre os controis favoritos"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Está entre os controis favoritos (posición: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Non está entre os controis favoritos"</string>
@@ -868,6 +872,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Téntao de novo"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Engadir controis"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controis"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Engadir saídas"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Seleccionouse 1 dispositivo"</string>
@@ -1033,4 +1039,6 @@
<skip />
<!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
<skip />
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d287f88..9e107ad 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"નિયંત્રણો ઉમેરવા માટે ઍપ પસંદ કરો"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# નિયંત્રણ ઉમેર્યું.}one{# નિયંત્રણ ઉમેર્યું.}other{# નિયંત્રણ ઉમેર્યા.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"કાઢી નાખ્યું"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> ઉમેરીએ?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"જ્યારે તમે <xliff:g id="APPNAME">%s</xliff:g> ઉમેરો, ત્યારે તે આ પૅનલમાં નિયંત્રણો અને કન્ટેન્ટ ઉમેરી શકે છે. કેટલીક ઍપમાં, અહીં કયા નિયંત્રણો દેખાય તે તમે પસંદ કરી શકો છો."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"મનપસંદમાં ઉમેર્યું"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"મનપસંદમાં ઉમેર્યું, સ્થાન <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"મનપસંદમાંથી કાઢી નાખ્યું"</string>
@@ -866,6 +868,7 @@
<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_add_another_app" msgid="8661172304650786705">"ઍપ ઉમેરો"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"આઉટપુટ ઉમેરો"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ગ્રૂપ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ડિવાઇસ પસંદ કર્યું"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"તમારી ઑફિસની પૉલિસી તમને માત્ર ઑફિસની પ્રોફાઇલ પરથી જ ફોન કૉલ કરવાની મંજૂરી આપે છે"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"ઑફિસની પ્રોફાઇલ પર સ્વિચ કરો"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"બંધ કરો"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8fe43ac..67408af 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"अपने-आप"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"किसी तरह की आवाज़ या वाइब्रेशन न हो"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"इससे किसी तरह की आवाज़ या वाइब्रेशन नहीं होता और बातचीत, सेक्शन में सबसे नीचे दिखती है"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"डिवाइस की सेटिंग के आधार पर, सूचना आने पर घंटी बज सकती है या वाइब्रेशन हो सकता है"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"डिवाइस की सेटिंग के आधार पर, सूचना आने पर घंटी बज सकती है या वाइब्रेशन हो सकता है. <xliff:g id="APP_NAME">%1$s</xliff:g> पर होने वाली बातचीत, डिफ़ॉल्ट रूप से बबल के तौर पर दिखती है."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"सिस्टम को यह तय करने की अनुमति दें कि इस सूचना के मिलने पर आवाज़ हो या वाइब्रेशन हो"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>स्थिति:</b> लेवल बढ़ाकर, डिफ़ॉल्ट के तौर पर सेट किया गया"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>स्थिति:</b> लेवल घटाकर, साइलेंट पर सेट किया गया"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"कंट्रोल जोड़ने के लिए ऐप्लिकेशन चुनें"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# कंट्रोल जोड़ा गया.}one{# कंट्रोल जोड़ा गया.}other{# कंट्रोल जोड़े गए.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"हटाया गया"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"पसंदीदा बनाया गया"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"पसंदीदा बनाया गया, क्रम संख्या <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"पसंदीदा से हटाया गया"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"गड़बड़ी हुई, फिर से कोशिश करें"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"कंट्राेल जोड़ें"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"कंट्रोल में बदलाव करें"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट जोड़ें"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ग्रुप"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिवाइस चुना गया"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> बैटरी बची है"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"अपने स्टाइलस को चार्ज करें"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलस की बैटरी कम है"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"वीडियो कैमरा"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"यह प्रोफ़ाइल होने पर कॉल नहीं की जा सकती"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ऑफ़िस की नीति के तहत, वर्क प्रोफ़ाइल होने पर ही फ़ोन कॉल किए जा सकते हैं"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"वर्क प्रोफ़ाइल पर स्विच करें"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"बंद करें"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d8d969b..46de94b 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Odabir aplikacije za dodavanje kontrola"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodana je # kontrola.}one{Dodana je # kontrola.}few{Dodane su # kontrole.}other{Dodano je # kontrola.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Uklonjeno"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Želite li dodati aplikaciju <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Kada dodate aplikaciju <xliff:g id="APPNAME">%s</xliff:g>, može dodati kontrole i sadržaj na ovu ploču. U nekim aplikacijama možete odabrati koje se kontrole prikazuju ovdje."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano u favorite"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano u favorite, položaj <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Uklonjeno iz favorita"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Pogreška, pokušajte ponovo"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Dodavanje aplikacije"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodavanje izlaza"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Odabran je jedan uređaj"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Vaša pravila za poslovne uređaje omogućuju vam upućivanje poziva samo s poslovnog profila"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Prijeđite na poslovni profil"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Zatvori"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 24d80ec..cabd898 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatikus"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nincs hang és rezgés"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nincs hang és rezgés, továbbá lejjebb jelenik meg a beszélgetések szakaszában"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Az eszközbeállítások alapján csöröghet és rezeghet"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Az eszközbeállítások alapján csöröghet és rezeghet. A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásban lévő beszélgetések alapértelmezés szerint buborékban jelennek meg."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"A rendszer határozza meg, hogy ez az értesítés adjon-e ki hangot, illetve rezegjen-e"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Állapot:</b> alapértelmezettre állítva"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Állapot:</b> némára állítva"</string>
@@ -802,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Válasszon alkalmazást a vezérlők hozzáadásához"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# vezérlő hozzáadva.}other{# vezérlő hozzáadva.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Eltávolítva"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Hozzáadja a(z) <xliff:g id="APPNAME">%s</xliff:g> alkalmazást?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"A(z) <xliff:g id="APPNAME">%s</xliff:g> hozzáadását követően az alkalmazás vezérlőelemeket és tartalmakat adhat hozzá ehhez a panelhez. Egyes alkalmazásokban kiválasztható, hogy mely vezérlőelemek jelenjenek meg itt."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Hozzáadva a kedvencekhez"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Hozzáadva a kedvencekhez <xliff:g id="NUMBER">%d</xliff:g>. helyen"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Eltávolítva a kedvencek közül"</string>
@@ -868,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Hiba történt. Próbálja újra."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Vezérlők hozzáadása"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Vezérlők szerkesztése"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Alkalmazás hozzáadása"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Kimenetek hozzáadása"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Csoport"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 eszköz kiválasztva"</string>
@@ -1023,14 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Akkumulátor töltöttségi szintje: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tegye töltőre az érintőceruzát"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Az érintőceruza töltöttsége alacsony"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nem lehet hívást kezdeményezni ebből a profilból"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"A munkahelyi házirend csak munkaprofilból kezdeményezett telefonhívásokat engedélyez"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Váltás munkaprofilra"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Bezárás"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7cf0c81..5b3cefb 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Ավտոմատ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Առանց ձայնի կամ թրթռոցի"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Առանց ձայնի և թրթռոցի, հայտնվում է զրույցների ցանկի ներքևում"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Կարող է զնգալ կամ թրթռալ՝ կախված սարքի կարգավորումներից"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Կարող է զնգալ կամ թրթռալ՝ կախված սարքի կարգավորումներից։ <xliff:g id="APP_NAME">%1$s</xliff:g>-ի զրույցներն ըստ կանխադրման հայտնվում են ամպիկների տեսքով։"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Թող համակարգն ավտոմատ որոշի՝ արդյոք այս ծանուցումը ձայնով, թե թրթռոցով է պետք մատուցել"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Կարգավիճակը․</b> բարձրացվել է և դարձել կանխադրված"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Կարգավիճակը․</b> իջեցվել է և դարձել անձայն"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Ընտրեք հավելված` կառավարման տարրեր ավելացնելու համար"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Ավելացվեց կառավարման # տարր։}one{Ավելացվեց կառավարման # տարր։}other{Ավելացվեց կառավարման # տարր։}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Հեռացված է"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Ավելացված է ընտրանիում"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ավելացված է ընտրանիում, դիրքը՝ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Հեռացված է ընտրանուց"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Ավելացնել կառավարման տարրեր"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Փոփոխել կառավարման տարրերը"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Ավելացրեք մուտքագրման սարքեր"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Խումբ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Ընտրված է 1 սարք"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ձեր ստիլուսը միացրեք լիցքավորիչի"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ստիլուսի մարտկոցի լիցքի ցածր մակարդակ"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Տեսախցիկ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Հնարավոր չէ զանգել այս պրոֆիլից"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Ձեր աշխատանքային կանոնների համաձայն՝ դուք կարող եք զանգեր կատարել աշխատանքային պրոֆիլից"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Անցնել աշխատանքային պրոֆիլ"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Փակել"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 877b7de..a00839f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatis"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tidak ada suara atau getaran"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tidak ada suara atau getaran dan ditampilkan lebih rendah di bagian percakapan"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Dapat berdering atau bergetar berdasarkan setelan perangkat"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Dapat berdering atau bergetar berdasarkan setelan perangkat. Percakapan <xliff:g id="APP_NAME">%1$s</xliff:g> ditampilkan sebagai balon secara default."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Biarkan sistem menentukan apakah notifikasi ini akan berbunyi atau bergetar"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Dipromosikan menjadi Default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Didemosikan menjadi Senyap"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Pilih aplikasi untuk menambahkan kontrol"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrol ditambahkan.}other{# kontrol ditambahkan.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Dihapus"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Difavoritkan"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Difavoritkan, posisi <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Batal difavoritkan"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Error, coba lagi"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Tambahkan kontrol"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit kontrol"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Tambahkan output"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 perangkat dipilih"</string>
@@ -1015,7 +1019,7 @@
<string name="rear_display_bottom_sheet_cancel" msgid="3461468855493357248">"Batal"</string>
<string name="rear_display_bottom_sheet_confirm" msgid="4383356544661421206">"Balik sekarang"</string>
<string name="rear_display_fold_bottom_sheet_title" msgid="6081542277622721548">"Bentangkan ponsel untuk selfie yang lebih baik"</string>
- <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Gunakan layar depan untuk selfie yang lebih baik?"</string>
+ <string name="rear_display_unfold_bottom_sheet_title" msgid="2137403802960396357">"Balik ke layar depan untuk selfie yang lebih bagus?"</string>
<string name="rear_display_bottom_sheet_description" msgid="1852662982816810352">"Gunakan kamera belakang untuk foto dengan resolusi lebih tinggi dan lebih lebar."</string>
<string name="rear_display_bottom_sheet_warning" msgid="800995919558238930"><b>"✱ Layar ini akan dinonaktifkan"</b></string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Perangkat foldable sedang dibentangkan"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Baterai tersisa <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hubungkan stilus ke pengisi daya"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Baterai stilus lemah"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Kamera video"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Tidak dapat melakukan panggilan dari profil ini"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Kebijakan kantor mengizinkan Anda melakukan panggilan telepon hanya dari profil kerja"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Beralih ke profil kerja"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 1e7934a..319988c 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Sjálfvirk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ekkert hljóð eða titringur"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ekkert hljóð eða titringur og birtist neðar í samtalshluta"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Gæti hringt eða titrað en það fer eftir stillingum tækisins"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Gæti hringt eða titrað en það fer eftir stillingum tækisins. Samtöl frá <xliff:g id="APP_NAME">%1$s</xliff:g> birtast sjálfkrafa í blöðru."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Láta kerfið ákvarða hvort hljóð eða titringur fylgir þessari tilkynningu"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Staða:</b> gerð sjálfgefin"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Staða:</b> var gerð þögul"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Veldu forrit til að bæta við stýringum"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# stýringu bætt við.}one{# stýringu bætt við.}other{# stýringum bætt við.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Fjarlægt"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Eftirlæti"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Eftirlæti, staða <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Fjarlægt úr eftirlæti"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Villa, reyndu aftur"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Bæta við stýringum"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Breyta stýringum"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Bæta við úttaki"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Hópur"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 tæki valið"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> hleðsla eftir á rafhlöðu"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tengdu pennann við hleðslutæki"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Rafhlaða pennans er að tæmast"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Kvikmyndatökuvél"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Ekki er hægt að hringja úr þessu sniði"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Vinnureglur gera þér aðeins kleift að hringja símtöl úr vinnusniði"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Skipta yfir í vinnusnið"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Loka"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 211d01d..bd5b706 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controllo aggiunto.}many{# controlli aggiunti.}other{# controlli aggiunti.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Rimosso"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Vuoi aggiungere <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Se la aggiungi, l\'app <xliff:g id="APPNAME">%s</xliff:g> può aggiungere controlli e contenuti a questo riquadro. In alcune app puoi scegliere quali controlli visualizzare qui."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Aggiunto ai preferiti"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Preferito, posizione <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Rimosso dai preferiti"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Errore, riprova"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Aggiungi controlli"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifica controlli"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Aggiungi app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Aggiungi uscite"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selezionato"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Le norme di lavoro ti consentono di fare telefonate soltanto dal profilo di lavoro"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Passa a profilo di lavoro"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Chiudi"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index fbec1f7..e1c20846 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"באופן אוטומטי"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ללא צליל או רטט"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ללא צליל או רטט ומופיעה למטה בקטע התראות השיחה"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ייתכן שיופעל צלצול או רטט בהתאם להגדרות במכשיר"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ייתכן שיופעל צלצול או רטט בהתאם להגדרות במכשיר. שיחות מהאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מופיעות בבועות כברירת מחדל."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"אפשר לתת למערכת לקבוע אם ההתראה הזאת צריכה להיות מלווה בצליל או ברטט"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>הסטטוס:</b> הועלה בדרגה ל\'ברירת מחדל\'"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>הסטטוס:</b> הורד בדרגה ל\'שקט\'"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"יש לבחור אפליקציה כדי להוסיף פקדים"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{נוסף אמצעי בקרה אחד (#).}one{נוספו # אמצעי בקרה.}two{נוספו # אמצעי בקרה.}other{נוספו # אמצעי בקרה.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"הוסר"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"סומן כמועדף"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"סומן כמועדף, במיקום <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"הוסר מהמועדפים"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"שגיאה, יש לנסות שוב"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"הוספת פקדים"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"עריכת פקדים"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"הוספת מכשירי פלט"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"קבוצה"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"נבחר מכשיר אחד"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"רמת הטעינה שנותרה בסוללה: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"כדאי לחבר את הסטיילוס למטען"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"הסוללה של הסטיילוס חלשה"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"מצלמת וידאו"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"אי אפשר להתקשר מהפרופיל הזה"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"המדיניות של מקום העבודה מאפשרת לך לבצע שיחות טלפון רק מפרופיל העבודה"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"מעבר לפרופיל עבודה"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"סגירה"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 8e66ec3..d29bebf 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"コントロールを追加するアプリの選択"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# 件のコントロールを追加しました。}other{# 件のコントロールを追加しました。}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"削除済み"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"<xliff:g id="APPNAME">%s</xliff:g> を追加しますか?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"<xliff:g id="APPNAME">%s</xliff:g> を追加することで、コントロールやコンテンツをこのパネルに追加できます。一部のアプリでは、ここに表示されるコントロールを選択できます。"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"お気に入りに追加済み"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"お気に入りに追加済み、位置: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"お気に入りから削除済み"</string>
@@ -866,6 +868,7 @@
<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_add_another_app" msgid="8661172304650786705">"アプリを追加"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"出力の追加"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"グループ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"選択したデバイス: 1 台"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"仕事用ポリシーでは、通話の発信を仕事用プロファイルからのみに制限できます"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"仕事用プロファイルに切り替える"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"閉じる"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 599b9d9..aae0473 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"აირჩიეთ აპი მართვის საშუალებების დასამატებლად"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{დაემატა მართვის # საშუალება.}other{დაემატა მართვის # საშუალება.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ამოიშალა"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"რჩეულებშია"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"რჩეულებშია, პოზიციაზე <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"რჩეულებიდან ამოღებულია"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"შეცდომა, ისევ ცადეთ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"მართვის საშუალებების დამატება"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"მართვის საშუალებათა რედაქტირება"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"მედია-გამოსავლების დამატება"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ჯგუფი"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"არჩეულია 1 მოწყობილობა"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"თქვენი სამსახურის წესები საშუალებას გაძლევთ, სატელეფონო ზარები განახორციელოთ მხოლოდ სამსახურის პროფილიდან"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"სამსახურის პროფილზე გადართვა"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"დახურვა"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 0dd10d0..a3b330c 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматты"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дыбыс не діріл болмайды."</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дыбыс не діріл болмайды, әңгімелер бөлімінің төмен жағында тұрады."</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Құрылғы параметрлеріне байланысты шырылдауы не дірілдеуі мүмкін"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Құрылғы параметрлеріне байланысты шырылдауы не дірілдеуі мүмкін. <xliff:g id="APP_NAME">%1$s</xliff:g> чаттары әдепкісінше қалқымалы етіп көрсетіледі."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Хабарландыру дыбысының немесе дірілдің қосылуын жүйе анықтайтын болады"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Күйі:</b> \"Әдепкі\" санатына көтерілген"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Күйі:</b> \"Үнсіз\" санатына төмендетілген"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Басқару элементтері қосылатын қолданбаны таңдаңыз"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# басқару элементі қосылды.}other{# басқару элементі қосылды.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Өшірілді"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Таңдаулыларға қосылды"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Таңдаулыларға қосылды, <xliff:g id="NUMBER">%d</xliff:g>-позиция"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Таңдаулылардан алып тасталды"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Қате шықты. Қайталап көріңіз."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Басқару элементтерін қосу"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Басқару элементтерін өзгерту"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Шығыс сигналдарды қосу"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Топ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 құрылғы таңдалды."</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Қалған батарея заряды: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусты зарядтағышқа жалғаңыз."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Стилус батареясының заряды аз"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Бейнекамера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Бұл профильден қоңырау шалу мүмкін емес"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Жұмыс саясатыңызға сәйкес тек жұмыс профилінен қоңырау шалуға болады."</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Жұмыс профиліне ауысу"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Жабу"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index eea029b..05d0429 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ស្វ័យប្រវត្តិ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"គ្មានសំឡេង ឬការញ័រទេ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"គ្មានសំឡេងឬការញ័រ និងបង្ហាញទាបជាងនៅក្នុងផ្នែកសន្ទនា"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"អាចរោទ៍ ឬញ័រ ដោយផ្អែកលើការកំណត់ឧបករណ៍"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"អាចរោទ៍ ឬញ័រ ដោយផ្អែកលើការកំណត់ឧបករណ៍។ ការសន្ទនាពីផ្ទាំងអណ្ដែត <xliff:g id="APP_NAME">%1$s</xliff:g> តាមលំនាំដើម។"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ឱ្យប្រព័ន្ធកំណត់ថាតើការជូនដំណឹងនេះគួរតែបន្លឺសំឡេង ឬញ័រ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ស្ថានភាព៖</b> បានដំឡើងទៅលំនាំដើម"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ស្ថានភាព៖</b> បានបញ្ចុះទៅស្ងាត់"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"ជ្រើសរើសកម្មវិធីដែលត្រូវបញ្ចូលផ្ទាំងគ្រប់គ្រង"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{បានបញ្ចូលការគ្រប់គ្រង #។}other{បានបញ្ចូលការគ្រប់គ្រង #។}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"បានដកចេញ"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"បានដាក់ជាសំណព្វ"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"បានដាក់ជាសំណព្វ ទីតាំងទី <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"បានដកចេញពីសំណព្វ"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"មានបញ្ហា សូមព្យាយាមម្តងទៀត"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"បញ្ចូលផ្ទាំងគ្រប់គ្រង"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"កែផ្ទាំងគ្រប់គ្រង"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"បញ្ចូលឧបករណ៍មេឌៀ"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ក្រុម"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"បានជ្រើសរើសឧបករណ៍ 1"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ថ្មនៅសល់ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ភ្ជាប់ប៊ិករបស់អ្នកជាមួយឆ្នាំងសាក"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ថ្មប៊ិកនៅសល់តិច"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"កាមេរ៉ាវីដេអូ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"មិនអាចហៅទូរសព្ទពីកម្រងព័ត៌មាននេះបានទេ"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"គោលការណ៍ការងាររបស់អ្នកអនុញ្ញាតឱ្យអ្នកធ្វើការហៅទូរសព្ទបានតែពីកម្រងព័ត៌មានការងារប៉ុណ្ណោះ"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ប្ដូរទៅកម្រងព័ត៌មានការងារ"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"បិទ"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 92956ac..74d875ec 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ನಿಯಂತ್ರಣವನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}one{# ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}other{# ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ಮೆಚ್ಚಲಾಗಿರುವುದು"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"ಮೆಚ್ಚಲಾಗಿರುವುದು, ಸ್ಥಾನ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ಮೆಚ್ಚಿನದಲ್ಲದ್ದು"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"ದೋಷ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ನಿಯಂತ್ರಣಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ಔಟ್ಪುಟ್ಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ಗುಂಪು"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ಸಾಧನವನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"ನಿಮ್ಮ ಕೆಲಸದ ನೀತಿಯು ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ನಿಂದ ಮಾತ್ರ ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ಗೆ ಬದಲಿಸಿ"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"ಮುಚ್ಚಿರಿ"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 0815dbf..ad5b523 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"자동"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"소리 또는 진동 없음"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"소리나 진동이 울리지 않으며 대화 섹션 하단에 표시됨"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"기기 설정에 따라 벨소리나 진동이 울릴 수 있음"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"기기 설정에 따라 벨소리나 진동이 울릴 수 있습니다. 기본적으로 <xliff:g id="APP_NAME">%1$s</xliff:g>의 대화는 대화창으로 표시됩니다."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"시스템에서 알림 시 소리 또는 진동을 사용할지 결정하도록 허용합니다."</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>상태:</b> 기본으로 높임"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>상태:</b> 무음으로 낮춤"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"컨트롤을 추가할 앱을 선택하세요"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{설정이 #개 추가되었습니다.}other{설정이 #개 추가되었습니다.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"삭제됨"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"즐겨찾기에 추가됨"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"즐겨찾기에 추가됨, 위치 <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"즐겨찾기에서 삭제됨"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"오류. 다시 시도하세요."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"컨트롤 추가"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"컨트롤 수정"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"출력 추가"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"그룹"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"기기 1대 선택됨"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"배터리 <xliff:g id="PERCENTAGE">%s</xliff:g> 남음"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"스타일러스를 충전기에 연결하세요"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"스타일러스 배터리 부족"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"비디오 카메라"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"이 프로필에서 전화를 걸 수 없음"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"직장 정책이 직장 프로필에서만 전화를 걸도록 허용합니다."</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"직장 프로필로 전환"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"닫기"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 4d026f5..b793e95 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматтык"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Үнү чыкпайт жана дирилдебейт"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Үнү чыкпайт же дирилдебейт жана сүйлөшүүлөр тизмесинин ылдый жагында көрүнөт"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Түзмөктүн параметрлерине жараша шыңгырап же дирилдеши мүмкүн"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Түзмөктүн параметрлерине жараша шыңгырап же дирилдеши мүмкүн. <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы сүйлөшүүлөр демейки шартта калкып чыкма билдирмелер болуп көрүнөт."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Билдирменин үнүн чыгартууну же басууну тутумга тапшырыңыз"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Абалы:</b> Демейкиге өзгөрдү"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Абалы:</b> Үнсүз абалга төмөндөдү"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Башкаруу элементтери кошула турган колдонмону тандоо"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# көзөмөл кошулду.}other{# көзөмөл кошулду.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Өчүрүлдү"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Сүйүктүүлөргө кошулду"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Сүйүктүүлөргө <xliff:g id="NUMBER">%d</xliff:g>-позицияга кошулду"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Сүйүктүүлөрдөн чыгарылды"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Ката, кайталап көрүңүз"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Башкаруу элементтерин кошуу"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Башкаруу элементтерин түзөтүү"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Медиа түзмөктөрдү кошуу"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Топ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 түзмөк тандалды"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Батареянын кубаты: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусту кубаттаңыз"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Стилустун батареясы отурайын деп калды"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Видео камера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Бул профилден чала албайсыз"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Жумуш саясатыңызга ылайык, жумуш профилинен гана чалууларды аткара аласыз"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Жумуш профилине которулуу"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Жабуу"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index e147c22..fd6e02a 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ອັດຕະໂນມັດ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ ແລະ ປາກົດຢູ່ທາງລຸ່ມຂອງພາກສ່ວນການສົນທະນາ"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ອາດສົ່ງສຽງ ຫຼື ສັ່ນເຕືອນໂດຍອ້າງອີງຈາກການຕັ້ງຄ່າອຸປະກອນ"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ອາດສົ່ງສຽງ ຫຼື ສັ່ນເຕືອນໂດຍອ້າງອີງຈາກການຕັ້ງຄ່າອຸປະກອນ. ການສົນທະນາຈາກ <xliff:g id="APP_NAME">%1$s</xliff:g> ຈະເປັນ bubble ຕາມຄ່າເລີ່ມຕົ້ນ."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ໃຫ້ລະບົບກຳນົດວ່າການແຈ້ງເຕືອນນິ້ຄວນມີສຽງ ຫຼື ສັ່ນເຕືອນຫຼືບໍ່"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ສະຖານະ:</b> ເລື່ອນລະດັບເປັນຄ່າເລີ່ມຕົ້ນແລ້ວ"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ສະຖານະ:</b> ຫຼຸດລະດັບເປັນປິດສຽງແລ້ວ"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"ເລືອກແອັບເພື່ອເພີ່ມການຄວບຄຸມ"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ເພີ່ມ # ການຄວບຄຸມແລ້ວ.}other{ເພີ່ມ # ການຄວບຄຸມແລ້ວ.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ລຶບອອກແລ້ວ"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ເພີ່ມລາຍການທີ່ມັກແລ້ວ"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"ເພີ່ມລາຍການທີ່ມັກແລ້ວ, ຕຳແໜ່ງ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ຍົກເລີກລາຍການທີ່ມັກແລ້ວ"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"ຜິດພາດ, ກະລຸນາລອງໃໝ່"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ເພີ່ມການຄວບຄຸມ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ແກ້ໄຂການຄວບຄຸມ"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ເພີ່ມເອົ້າພຸດ"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ກຸ່ມ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"ເລືອກ 1 ອຸປະກອນແລ້ວ"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ແບັດເຕີຣີເຫຼືອ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ເຊື່ອມຕໍ່ປາກກາຂອງທ່ານກັບສາຍສາກ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ແບັດເຕີຣີປາກກາເຫຼືອໜ້ອຍ"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"ກ້ອງວິດີໂອ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ບໍ່ສາມາດໂທຈາກໂປຣໄຟລ໌ນີ້ໄດ້"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ນະໂຍບາຍບ່ອນເຮັດວຽກຂອງທ່ານອະນຸຍາດໃຫ້ທ່ານໂທລະສັບໄດ້ຈາກໂປຣໄຟລ໌ບ່ອນເຮັດວຽກເທົ່ານັ້ນ"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ສະຫຼັບໄປໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"ປິດ"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0d5c045..737e652 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Pasirinkite programą, kad pridėtumėte valdiklių"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Pridėtas # valdiklis.}one{Pridėtas # valdiklis.}few{Pridėti # valdikliai.}many{Pridėta # valdiklio.}other{Pridėta # valdiklių.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Pašalinta"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Pridėti „<xliff:g id="APPNAME">%s</xliff:g>“?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Pridėjus programą „<xliff:g id="APPNAME">%s</xliff:g>“, ji gali pridėti valdiklių ir turinio prie šio skydelio. Kai kuriose programose galite pasirinkti, kurie valdikliai čia rodomi."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Įtraukta į mėgstamiausius"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Įtraukta į mėgstamiausius, padėtis: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Pašalinta iš mėgstamiausių"</string>
@@ -866,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Klaida, bandykite dar kartą"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Pridėti valdiklių"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Redaguoti valdiklius"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Pridėti programą"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Išvesčių pridėjimas"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupė"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Pasirinktas 1 įrenginys"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Pagal jūsų darbo politiką galite skambinti telefonu tik iš darbo profilio"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Perjungti į darbo profilį"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Uždaryti"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index ae22afd..8ffbf2c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automātiski"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Nav skaņas signāla vai vibrācijas"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nav skaņas signāla vai vibrācijas, kā arī atrodas tālāk sarunu sadaļā"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Atkarībā no iestatījumiem var zvanīt vai vibrēt"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Atkarībā no ierīces iestatījumiem var zvanīt vai vibrēt. Sarunas no lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> pēc noklusējuma tiek parādītas burbulī."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Iestatiet, lai sistēma noteiktu, vai šim paziņojumam būs skaņa vai vibrācija"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Statuss:</b> svarīgums paaugstināts līdz noklusējumam"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Statuss:</b> svarīgums pazemināts, un paziņojums tiks rādīts bez skaņas"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Izvēlieties lietotni, lai pievienotu vadīklas"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Pievienota # vadīkla.}zero{Pievienotas # vadīklas.}one{Pievienota # vadīkla.}other{Pievienotas # vadīklas.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Noņemta"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Pievienota izlasei"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Pievienota izlasei, <xliff:g id="NUMBER">%d</xliff:g>. pozīcija"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Noņemta no izlases"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Radās kļūda. Mēģiniet vēlreiz."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Pievienot vadīklas"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Rediģēt vadīklas"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Izejas ierīču pievienošana"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Atlasīta viena ierīce"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Atlikušais uzlādes līmenis: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pievienojiet skārienekrāna pildspalvu lādētājam"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Zems skārienekrāna pildspalvas akumulatora līmenis"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nevar zvanīt no šī profila"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Saskaņā ar jūsu darba politiku tālruņa zvanus drīkst veikt tikai no darba profila"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Pārslēgties uz darba profilu"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Aizvērt"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index afe276f..5052c2c 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматски"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибрации"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибрации и се појавува подолу во делот со разговори"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да ѕвони или вибрира во зависност од поставките на уредот"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да ѕвони или вибрира во зависност од поставките на уредот. Стандардно, разговорите од <xliff:g id="APP_NAME">%1$s</xliff:g> се во балончиња."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Дозволете системот да определи дали известувањево треба да испушти звук или да вибрира"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> поставено на „Стандардно“"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> намалено на „Тивко“"</string>
@@ -802,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Изберете апликација за да додадете контроли"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Додадена е # контрола.}one{Додадени се # контрола.}other{Додадени се # контроли.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Отстранета"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Да се додаде <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Кога ќе ја додадете <xliff:g id="APPNAME">%s</xliff:g>, таа ќе може да додава контроли и содржини на таблава. Кај некои апликации, може да изберете кои контроли ќе се прикажуваат тука."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Омилена"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Омилена, позиција <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Неомилена"</string>
@@ -868,6 +868,7 @@
<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_add_another_app" msgid="8661172304650786705">"Додајте апликација"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Додајте излези"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Избран е 1 уред"</string>
@@ -1023,14 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Преостаната батерија: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поврзете го пенкалото со полнач"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Слаба батерија на пенкало"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Не можете да се јавите од профилов"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Вашето работно правило ви дозволува да упатувате повици само од работниот профил"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Префрли се на работен профил"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затвори"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 1e23455..d0803b1 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"നിയന്ത്രണങ്ങൾ ചേർക്കാൻ ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# നിയന്ത്രണം ചേർത്തു.}other{# നിയന്ത്രണങ്ങൾ ചേർത്തു.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"നീക്കം ചെയ്തു"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"പ്രിയപ്പെട്ടതാക്കി"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"പ്രിയപ്പെട്ടതാക്കി, സ്ഥാനം <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"പ്രിയപ്പെട്ടതല്ലാതാക്കി"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"പിശക്, വീണ്ടും ശ്രമിക്കുക"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"നിയന്ത്രണങ്ങൾ എഡിറ്റ് ചെയ്യുക"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ഔട്ട്പുട്ടുകൾ ചേർക്കുക"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ഗ്രൂപ്പ്"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"ഒരു ഉപകരണം തിരഞ്ഞെടുത്തു"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"ഔദ്യോഗിക പ്രൊഫൈലിൽ നിന്ന് മാത്രം ഫോൺ കോളുകൾ ചെയ്യാനാണ് നിങ്ങളുടെ ഔദ്യോഗിക നയം അനുവദിക്കുന്നത്"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് മാറുക"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"അടയ്ക്കുക"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 4d06e1f..f4ace18 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автомат"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Дуу эсвэл чичиргээ байхгүй"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дуу эсвэл чичиргээ байхгүй бөгөөд харилцан ярианы хэсгийн доод талд харагдана"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Төхөөрөмжийн тохиргоонд тулгуурлан хонх дуугаргах эсвэл чичиргэж болзошгүй"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Төхөөрөмжийн тохиргоонд тулгуурлан хонх дуугаргах эсвэл чичиргэж болзошгүй. <xliff:g id="APP_NAME">%1$s</xliff:g>-н харилцан яриаг өгөгдмөлөөр бөмбөлөг болгоно."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Энэ мэдэгдэл дуу гаргах эсвэл чичрэх эсэхийг системээр тодорхойлуулаарай"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Төлөв:</b> Өгөгдмөл болгож дэвшүүлсэн"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Төлөв:</b> Чимээгүй болгож зэрэглэлийг нь бууруулсан"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Хяналтууд нэмэхийн тулд аппыг сонгоно уу"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# хяналт нэмсэн.}other{# хяналт нэмсэн.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Хассан"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Дуртай гэж тэмдэглэсэн"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>-р байршилд дуртай гэж тэмдэглэсэн"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Дургүй гэж тэмдэглэсэн"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Алдаа гарав, дахин оролдоно уу"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Хяналт нэмэх"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Хяналтыг өөрчлөх"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Гаралт нэмэх"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Бүлэг"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 төхөөрөмж сонгосон"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> батарей үлдлээ"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Мэдрэгч үзгээ цэнэглэгчтэй холбоорой"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Мэдрэгч үзэгний батарей бага байна"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Видео камер"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Энэ профайлаас залгах боломжгүй"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Таны ажлын бодлого танд зөвхөн ажлын профайлаас утасны дуудлага хийхийг зөвшөөрдөг"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Ажлын профайл руу сэлгэх"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Хаах"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 2013879..dd6286d 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ऑटोमॅटिक"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"आवाज किंवा व्हायब्रेशन नाही"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"आवाज किंवा व्हायब्रेशन नाही आणि संभाषण विभागात सर्वात तळाशी दिसते"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"डिव्हाइस सेटिंग्जनुसार रिंग किंवा व्हायब्रेट होऊ शकतो"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"डिव्हाइस सेटिंग्जनुसार रिंग किंवा व्हायब्रेट होऊ शकतो. <xliff:g id="APP_NAME">%1$s</xliff:g> मधील संभाषणे बाय डीफॉल्ट बबल होतात."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ही सूचना मिळाल्यावर आवाज व्हावा की व्हायब्रेशन व्हावे ते सिस्टममध्ये नमूद करा"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>स्थिती</b> ही डीफॉल्ट म्हणून प्रमोट केली गेली"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>स्थिती</b> ला सायलंट म्हणून डीमोट केले गेले"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"नियंत्रणे जोडण्यासाठी ॲप निवडा"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# नियंत्रण जोडले आहे.}other{# नियंत्रणे जोडली आहेत.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"काढून टाकले"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"आवडले"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"आवडले, स्थान <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"नावडले"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"एरर, पुन्हा प्रयत्न करा"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"नियंत्रणे जोडा"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"नियंत्रणे संपादित करा"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट जोडा"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"गट"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"एक डिव्हाइस निवडले"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> बॅटरी शिल्लक आहे"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"तुमचे स्टायलस चार्जरशी कनेक्ट करा"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"स्टायलस बॅटरी कमी आहे"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"व्हिडिओ कॅमेरा"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"या प्रोफाइलवरून कॉल करू शकत नाही"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"तुमचे कामाशी संबंधित धोरण तुम्हाला फक्त कार्य प्रोफाइलवरून फोन कॉल करन्याची अनुमती देते"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"कार्य प्रोफाइलवर स्विच करा"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"बंद करा"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6930fac9..2782925 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Pilih apl untuk menambahkan kawalan"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kawalan ditambah.}other{# kawalan ditambah.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Dialih keluar"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Digemari"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Digemari, kedudukan <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Dinyahgemari"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Ralat, cuba lagi"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Tambah kawalan"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edit kawalan"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Tambah output"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Kumpulan"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 peranti dipilih"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Dasar kerja anda membenarkan anda membuat panggilan telefon hanya daripada profil kerja"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Tukar kepada profil kerja"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Tutup"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 3a7cf14..f875654 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"အလိုအလျောက်"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ၊ စကားဝိုင်းကဏ္ဍ၏ အောက်ပိုင်းတွင် မြင်ရသည်"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"စက်ပစ္စည်း ဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် (သို့) တုန်ခါနိုင်သည်"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"စက်ပစ္စည်းဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် (သို့) တုန်ခါနိုင်သည်။ မူရင်းသတ်မှတ်ချက်အဖြစ် <xliff:g id="APP_NAME">%1$s</xliff:g> မှ စကားဝိုင်းများကို ပူဖောင်းကွက်ဖြင့် ပြသည်။"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ဤအကြောင်းကြားချက်က အသံ သို့မဟုတ် တုန်ခါမှု ပေးရန် သင့်/မသင့်ကို စနစ်က ဆုံးဖြတ်ပါစေ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>အခြေအနေ-</b> မူရင်းသို့ ချိန်ညှိထားသည်"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>အခြေအနေ-</b> အသံတိတ်ခြင်းသို့ ပြန်ချိန်ညှိထားသည်"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"ထိန်းချုပ်မှုများထည့်ရန် အက်ပ်ရွေးခြင်း"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ထိန်းချုပ်ခလုတ် # ခု ထည့်ထားသည်။}other{ထိန်းချုပ်ခလုတ် # ခု ထည့်ထားသည်။}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ဖယ်ရှားထားသည်"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"အကြိုက်ဆုံးတွင် ထည့်ထားသည်"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"အကြိုက်ဆုံးတွင် ထည့်ထားသည်၊ အဆင့် <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"အကြိုက်ဆုံးမှ ဖယ်ရှားထားသည်"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"မှားသွားသည်၊ ပြန်စမ်းကြည့်ပါ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ထိန်းချုပ်မှုများ ထည့်ရန်"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ထိန်းချုပ်မှုများ ပြင်ရန်"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"မီဒီယာအထွက်များ ထည့်ရန်"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"အုပ်စု"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"စက်ပစ္စည်း ၁ ခုကို ရွေးချယ်ထားသည်"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"ဘက်ထရီ <xliff:g id="PERCENTAGE">%s</xliff:g> ကျန်သေးသည်"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"စတိုင်လပ်စ်ကို အားသွင်းကိရိယာနှင့် ချိတ်ဆက်ခြင်း"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"စတိုင်လပ်စ် ဘက်ထရီ အားနည်းနေသည်"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"ဗီဒီယိုကင်မရာ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ဤပရိုဖိုင်မှ ခေါ်ဆို၍ မရပါ"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"သင့်အလုပ်မူဝါဒသည် သင့်အား အလုပ်ပရိုဖိုင်မှသာ ဖုန်းခေါ်ဆိုခွင့် ပြုသည်"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"အလုပ်ပရိုဖိုင်သို့ ပြောင်းရန်"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"ပိတ်ရန်"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5fc1884..3ea94d9 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatisk"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibrering"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibrering, og vises lavere i samtaledelen"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Kan ringe eller vibrere basert på enhetsinnstillingene"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Kan ringe eller vibrere basert på enhetsinnstillingene. Samtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som standard som bobler."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"La systemet velge om dette varselet skal lage lyd eller vibrere"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Oppgradert til standard"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Nedgradert til lydløst"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Velg en app for å legge til kontroller"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontroll er lagt til.}other{# kontroller er lagt til.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Fjernet"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Favoritt"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favoritt, posisjon <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Fjernet som favoritt"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"En feil oppsto. Prøv på nytt"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Legg til kontroller"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Endre kontroller"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Legg til utenheter"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Gruppe"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet er valgt"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> batteri gjenstår"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koble pekepennen til en lader"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Det er lite batteri i pekepennen"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Kan ikke ringe fra denne profilen"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Som følge av jobbreglene dine kan du bare starte telefonanrop fra jobbprofilen."</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Bytt til jobbprofilen"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Lukk"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index d74d153..94f0060 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"स्वचालित"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"बज्दैन पनि, भाइब्रेट पनि हुँदैन"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"बज्दैन पनि, भाइब्रेट पनि हुँदैन र वार्तालाप खण्डको तलतिर देखा पर्छ"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"डिभाइसको सेटिङका आधारमा घन्टी बज्न वा भाइब्रेट हुन सक्छ"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"डिभाइसको सेटिङका आधारमा घन्टी बज्न वा कम्पन हुन सक्छ। <xliff:g id="APP_NAME">%1$s</xliff:g> मार्फत गरिएका वार्तालापहरू स्वतः बबलमा देखिन्छन्।"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"सिस्टमलाई यो सूचना आउँदा ध्वनि बज्नु पर्छ वा कम्पन हुनु पर्छ भन्ने कुराको निधो गर्न दिनुहोस्"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>स्थिति:</b> सूचनालाई महत्त्वपूर्ण ठानी डिफल्ट मोडमा सेट गरिएको छ"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>स्थिति:</b> सूचनालाई कम महत्त्वपूर्ण ठानी साइलेन्ट मोडमा सेट गरिएको छ"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"कन्ट्रोल थप्नु पर्ने एप छान्नुहोस्"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# कन्ट्रोल हालियो।}other{# वटा कन्ट्रोल हालियो।}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"हटाइएको"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"मनपराइएको"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"मन पराइएका कुराहरूको <xliff:g id="NUMBER">%d</xliff:g> औँ स्थानमा"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"मन पर्ने कुराहरूको सूचीमा नराखिएको"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"त्रुटि भयो, फेरि प्रयास गर्नु…"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"कन्ट्रोल थप्नुहोस्"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"कन्ट्रोल सम्पादन गर्नुहोस्"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट यन्त्रहरू थप्नुहोस्"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"समूह"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"१ यन्त्र चयन गरियो"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ब्याट्री बाँकी छ"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"आफ्नो स्टाइलस चार्जरमा कनेक्ट गर्नुहोस्"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलसको ब्याट्री लो छ"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"भिडियो क्यामेरा"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"यो प्रोफाइलबाट कल गर्न सकिँदैन"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"तपाईंको कामसम्बन्धी नीतिअनुसार कार्य प्रोफाइलबाट मात्र फोन कल गर्न सकिन्छ"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"कार्य प्रोफाइल प्रयोग गर्नुहोस्"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"बन्द गर्नुहोस्"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 1b3cefd..161e8ac 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Kies de app waaraan je bedieningselementen wilt toevoegen"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# bedieningselement toegevoegd.}other{# bedieningselementen toegevoegd.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Verwijderd"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Gemarkeerd als favoriet"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Gemarkeerd als favoriet, positie <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Verwijderd als favoriet"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer het opnieuw"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Bedieningselementen toevoegen"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Bedieningselementen bewerken"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Uitvoer toevoegen"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Groep"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Eén apparaat geselecteerd"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Op basis van je werkbeleid kun je alleen bellen vanuit het werkprofiel"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Overschakelen naar werkprofiel"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Sluiten"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 37b1990..5396ede 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ସ୍ୱଚାଳିତ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ ଏବଂ ବାର୍ତ୍ତାଳାପ ବିଭାଗର ନିମ୍ନରେ ଦେଖାଯାଏ"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ଡିଭାଇସ ସେଟିଂସ ଆଧାରରେ ରିଂ କିମ୍ବା ଭାଇବ୍ରେଟ ହୋଇପାରେ"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ଡିଭାଇସ ସେଟିଂସ ଆଧାରରେ ରିଂ କିମ୍ବା ଭାଇବ୍ରେଟ ହୋଇପାରେ। ଡିଫଲ୍ଟ ଭାବରେ <xliff:g id="APP_NAME">%1$s</xliff:g>ରୁ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ବବଲ ଭାବେ ଦେଖାଯାଏ।"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ଏହି ବିଜ୍ଞପ୍ତି ପ୍ରାପ୍ତ ହେବା ସମୟରେ ସାଉଣ୍ଡ ହେବା ଉଚିତ ନା ଭାଇବ୍ରେସନ୍ ତାହା ସିଷ୍ଟମକୁ ସ୍ଥିର କରିବାକୁ ଦିଅନ୍ତୁ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ସ୍ଥିତି:</b> ଡିଫଲ୍ଟକୁ ପ୍ରମୋଟ୍ କରାଯାଇଛି"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ସ୍ଥିତି:</b> ନୀରବକୁ ଡିମୋଟ୍ କରାଯାଇଛି"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଯୋଗ କରିବାକୁ ଆପ୍ ବାଛନ୍ତୁ"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{#ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।}other{#ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"କାଢ଼ି ଦିଆଯାଇଛି"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ପସନ୍ଦ କରାଯାଇଛି"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"ପସନ୍ଦ କରାଯାଇଛି, ସ୍ଥିତି <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ନାପସନ୍ଦ କରାଯାଇଛି"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"ତ୍ରୁଟି ହୋଇଛି, ପୁଣି ଚେଷ୍ଟା କର"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଏଡିଟ କରନ୍ତୁ"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ଆଉଟପୁଟ୍ ଯୋଗ କରନ୍ତୁ"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ଗୋଷ୍ଠୀ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1ଟି ଡିଭାଇସ୍ ଚୟନ କରାଯାଇଛି"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ବେଟେରୀ ଚାର୍ଜ ବାକି ଅଛି"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ଏକ ଚାର୍ଜର ସହ ଆପଣଙ୍କ ଷ୍ଟାଇଲସକୁ କନେକ୍ଟ କରନ୍ତୁ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ଷ୍ଟାଇଲସ ବେଟେରୀର ଚାର୍ଜ କମ ଅଛି"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"ଭିଡିଓ କେମେରା"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ଏହି ପ୍ରୋଫାଇଲରୁ କଲ କରାଯାଇପାରିବ ନାହିଁ"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ଆପଣଙ୍କ ୱାର୍କ ନୀତି ଆପଣଙ୍କୁ କେବଳ ୱାର୍କ ପ୍ରୋଫାଇଲରୁ ଫୋନ କଲ କରିବାକୁ ଅନୁମତି ଦିଏ"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ୱାର୍କ ପ୍ରୋଫାଇଲକୁ ସ୍ୱିଚ କରନ୍ତୁ"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"ବନ୍ଦ କରନ୍ତୁ"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 58df165..10c89f2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"ਸਵੈਚਲਿਤ"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਵਿੱਚ ਹੇਠਲੇ ਪਾਸੇ ਦਿਸਦੀਆਂ ਹਨ"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"ਡੀਵਾਈਸ ਸੈਟਿੰਗਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਘੰਟੀ ਵੱਜ ਸਕਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਹੋ ਸਕਦੀ ਹੈ"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"ਡੀਵਾਈਸ ਸੈਟਿੰਗਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਘੰਟੀ ਵੱਜ ਸਕਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਹੋ ਸਕਦੀ ਹੈ। ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਤੌਰ \'ਤੇ <xliff:g id="APP_NAME">%1$s</xliff:g> ਬਬਲ ਤੋਂ ਗੱਲਾਂਬਾਤਾਂ।"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"ਸਿਸਟਮ ਨੂੰ ਨਿਰਧਾਰਤ ਕਰਨ ਦਿਓ ਕਿ ਇਸ ਸੂਚਨਾ ਲਈ ਕੋਈ ਧੁਨੀ ਵਜਾਉਣੀ ਚਾਹੀਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>ਸਥਿਤੀ:</b> ਦਰਜਾ ਵਧਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>ਸਥਿਤੀ:</b> ਦਰਜਾ ਘਟਾ ਕੇ ਸ਼ਾਂਤ \'ਤੇ ਸੈੱਟ ਕੀਤਾ ਗਿਆ"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।}one{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।}other{# ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤੇ ਗਏ।}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ਹਟਾਇਆ ਗਿਆ"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"ਮਨਪਸੰਦ ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ, ਸਥਾਨ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ਮਨਪਸੰਦ ਵਿੱਚੋਂ ਹਟਾਇਆ ਗਿਆ"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"ਗੜਬੜ, ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ਕੰਟਰੋਲਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ਆਊਟਪੁੱਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"ਗਰੁੱਪ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ਡੀਵਾਈਸ ਨੂੰ ਚੁਣਿਆ ਗਿਆ"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ ਬਾਕੀ"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ਆਪਣੇ ਸਟਾਈਲਸ ਨੂੰ ਚਾਰਜਰ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ ਘੱਟ ਹੈ"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"ਵੀਡੀਓ ਕੈਮਰਾ"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"ਇਸ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਕਾਲ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"ਤੁਹਾਡੀ ਕਾਰਜ ਨੀਤੀ ਤੁਹਾਨੂੰ ਸਿਰਫ਼ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਹੀ ਫ਼ੋਨ ਕਾਲਾਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"ਬੰਦ ਕਰੋ"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index a7c24f8..fbe5e9b 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatycznie"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez dźwięku i wibracji"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brak dźwięku i wibracji, wyświetla się niżej w sekcji rozmów"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Może włączać dzwonek lub wibracje w zależności od ustawień urządzenia"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Może włączyć dzwonek lub wibracje w zależności od ustawień urządzenia. Rozmowy z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> są domyślnie wyświetlane jako dymki."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Pozwól systemowi decydować, czy o powiadomieniu powinien informować dźwięk czy wibracja"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stan:</b> zmieniony na Domyślny"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stan:</b> zmieniono na Ciche"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Wybierz aplikację, do której chcesz dodać elementy sterujące"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Dodano # element sterujący.}few{Dodano # elementy sterujące.}many{Dodano # elementów sterujących.}other{Dodano # elementu sterującego.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Usunięto"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano do ulubionych"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano do ulubionych, pozycja <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Usunięto z ulubionych"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Błąd, spróbuj ponownie"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj elementy sterujące"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edytuj elementy sterujące"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodaj urządzenia wyjściowe"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupa"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Wybrano 1 urządzenie"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Pozostało <xliff:g id="PERCENTAGE">%s</xliff:g> baterii"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Podłącz rysik do ładowarki"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Słaba bateria w rysiku"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Kamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nie można nawiązać połączenia z tego profilu"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Zasady obowiązujące w firmie zezwalają na nawiązywanie połączeń telefonicznych tylko w profilu służbowym"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Przełącz na profil służbowy"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zamknij"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e56a7c7..f1adbfd 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Pode vibrar ou tocar com base nas configurações do dispositivo"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Pode vibrar ou tocar com base nas configurações do dispositivo. As conversas do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem em balões por padrão."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faça com que o sistema determine se a notificação resultará em som ou vibração"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promovida a Padrão"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> rebaixada a Silenciosa"</string>
@@ -802,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar o app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Quando você adiciona o app <xliff:g id="APPNAME">%s</xliff:g>, ele pode incluir controles e conteúdo neste painel. Em alguns casos, é possível escolher quais controles aparecem aqui."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Removido dos favoritos"</string>
@@ -868,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Adicionar app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adicionar saídas"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
@@ -1023,14 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateria restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Não é possível fazer uma ligação por este perfil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Sua política de trabalho só permite fazer ligações pelo perfil de trabalho"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Alternar para o perfil de trabalho"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fechar"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 7f1ce90..4aa89ea 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controlo adicionado.}many{# controlos adicionados.}other{# controlos adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado aos favoritos"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionados aos favoritos, posição <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Removido dos favoritos"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controlos"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controlos"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adicione saídas"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"A sua Política de Trabalho só lhe permite fazer chamadas telefónicas a partir do perfil de trabalho"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Mudar para perfil de trabalho"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Fechar"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e56a7c7..f1adbfd 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automática"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Pode vibrar ou tocar com base nas configurações do dispositivo"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Pode vibrar ou tocar com base nas configurações do dispositivo. As conversas do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem em balões por padrão."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Faça com que o sistema determine se a notificação resultará em som ou vibração"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> promovida a Padrão"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> rebaixada a Silenciosa"</string>
@@ -802,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# controle adicionado.}one{# controle adicionado.}many{# de controles adicionados.}other{# controles adicionados.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Removido"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Adicionar o app <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Quando você adiciona o app <xliff:g id="APPNAME">%s</xliff:g>, ele pode incluir controles e conteúdo neste painel. Em alguns casos, é possível escolher quais controles aparecem aqui."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Adicionado como favorito"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Adicionado como favorito (posição <xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Removido dos favoritos"</string>
@@ -868,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Adicionar app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adicionar saídas"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 dispositivo selecionado"</string>
@@ -1023,14 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Bateria restante: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Não é possível fazer uma ligação por este perfil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Sua política de trabalho só permite fazer ligações pelo perfil de trabalho"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Alternar para o perfil de trabalho"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Fechar"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index a4c66ec..f8147464 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automat"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Fără sunet sau vibrații"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Fără sunet sau vibrații și apare în partea de jos a secțiunii de conversație"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Poate să sune sau să vibreze, în funcție de setările dispozitivului"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Poate să sune sau să vibreze, în funcție de setările dispozitivului. Conversațiile din balonul <xliff:g id="APP_NAME">%1$s</xliff:g> în mod prestabilit."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Solicită-i sistemului să stabilească dacă această notificare e sonoră sau cu vibrații."</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stare:</b> promovată la prestabilită"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stare:</b> setată ca Silențioasă"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Alege aplicația pentru a adăuga comenzi"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S-a adăugat # comandă.}few{S-au adăugat # comenzi.}other{S-au adăugat # de comenzi.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Eliminată"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Marcată ca preferată"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Marcată ca preferată, poziția <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"S-a anulat marcarea ca preferată"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Eroare, încearcă din nou"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Adaugă comenzi"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Editează comenzile"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adaugă ieșiri"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"S-a selectat un dispozitiv"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> baterie rămasă"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conectează-ți creionul la un încărcător"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Nivelul bateriei creionului este scăzut"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Cameră video"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nu poți iniția apeluri din acest profil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Politica privind activitatea îți permite să efectuezi apeluri telefonice numai din profilul de serviciu"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Comută la profilul de serviciu"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Închide"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index d4dddbe..338df67 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Чтобы добавить виджеты управления, выберите приложение"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Добавлен # элемент управления.}one{Добавлен # элемент управления.}few{Добавлено # элемента управления.}many{Добавлено # элементов управления.}other{Добавлено # элемента управления.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Удалено"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Добавлено в избранное"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Добавлено в избранное на позицию <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Не добавлено в избранное"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Ошибка. Повторите попытку."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Добавить виджеты"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Изменить виджеты"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Добавление устройств вывода"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Группа"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Выбрано 1 устройство"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Согласно правилам вашей организации вы можете совершать телефонные звонки только из рабочего профиля."</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в рабочий профиль"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрыть"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 838f4ee..8ea1695 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"පාලන එක් කිරීමට යෙදුම තෝරා ගන්න"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# පාලනයක් එක් කර ඇත.}one{පාලන #ක් එක් කර ඇත.}other{පාලන #ක් එක් කර ඇත.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ඉවත් කළා"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ප්රියතම කළා"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"ප්රියතම කළා, තත්ත්ව <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ප්රියතම වෙතින් ඉවත් කළා"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"දෝෂයකි, නැවත උත්සාහ කරන්න"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"පාලන එක් කරන්න"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"පාලන සංස්කරණය කරන්න"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ප්රතිදාන එක් කරන්න"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"සමූහය"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"උපාංග 1ක් තෝරන ලදී"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"ඔබේ වැඩ ප්රතිපත්තිය ඔබට කාර්යාල පැතිකඩෙන් පමණක් දුරකථන ඇමතුම් ලබා ගැනීමට ඉඩ සලසයි"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"කාර්යාල පැතිකඩ වෙත මාරු වන්න"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"වසන්න"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 92448f8..caf0736 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikáciu, ktorej ovládače si chcete pridať"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Bol pridaný # ovládací prvok.}few{Boli pridané # ovládacie prvky.}many{# controls added.}other{Bolo pridaných # ovládacích prvkov.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Odstránené"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Pridané medzi obľúbené"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Pridané medzi obľúbené, pozícia <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Odstránené z obľúbených"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Chyba, skúste to znova"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Pridať ovládače"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládače"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Pridanie výstupov"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 vybrané zariadenie"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"Pracovné pravidlá vám umožňujú telefonovať iba v pracovnom profile"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"Prepnúť na pracovný profil"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"Zavrieť"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 4658ba6..bf6a91e 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Samodejno"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Brez zvočnega opozarjanja ali vibriranja."</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brez zvočnega opozarjanja ali vibriranja, prikaz nižje v razdelku Pogovor."</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Zvonjenje ali vibriranje je omogočeno na podlagi nastavitev naprave."</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Zvonjenje ali vibriranje je omogočeno na podlagi nastavitev naprave. Pogovori v aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> so privzeto prikazani v oblačkih."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Naj sistem določi, ali ob prejemu tega obvestila naprava predvaja zvok ali zavibrira"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Stanje:</b> Uvrščeno med privzeta obvestila"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Stanje:</b> Uvrščeno med obvestila brez zvoka"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Izberite aplikacijo za dodajanje kontrolnikov"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrolnik je dodan.}one{# kontrolnik je dodan.}two{# kontrolnika sta dodana.}few{# kontrolniki so dodani.}other{# kontrolnikov je dodanih.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Odstranjeno"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Dodano med priljubljene"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Dodano med priljubljene, položaj <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Odstranjeno iz priljubljenih"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Napaka, poskusite znova"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodajte kontrolnike"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Uredite kontrolnike"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodajanje izhodov"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Skupina"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Izbrana je ena naprava"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Preostanek energije baterije: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisalo s polnilnikom."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Skoraj prazna baterija pisala"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Ni mogoče klicati iz tega profila"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Službeni pravilnik dovoljuje opravljanje telefonskih klicev le iz delovnega profila."</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Preklopi na delovni profil"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Zapri"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 98bff8b..34bbf78 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatike"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Asnjë tingull ose dridhje"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Asnjë tingull ose dridhje dhe shfaqet më poshtë në seksionin e bisedave"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Mund të bjerë zilja ose të dridhet në bazë të cilësimeve të pajisjes"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Mund të bjerë zilja ose të dridhet në bazë të cilësimeve të pajisjes. Bisedat nga flluska e <xliff:g id="APP_NAME">%1$s</xliff:g> si parazgjedhje."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Kërkoji sistemit të përcaktojë nëse ky njoftim duhet të lëshojë tingull apo dridhje"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Statusi:</b> Promovuar si parazgjedhje"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Statusi:</b> Ulur në nivel si në heshtje"</string>
@@ -802,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Zgjidh aplikacionin për të shtuar kontrollet"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{U shtua # kontroll.}other{U shtuan # kontrolle.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"E hequr"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Të shtohet <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Kur shton <xliff:g id="APPNAME">%s</xliff:g>, ai mund t\'i shtojë kontrolle dhe përmbajtje këtij paneli. Në disa aplikacione, mund të zgjedhësh se cilat kontrolle shfaqen këtu."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"E shtuar te të preferuarat"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"E shtuar te të preferuarat, pozicioni <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"E hequr nga të preferuarat"</string>
@@ -868,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Gabim, provo sërish"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Shto kontrollet"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifiko kontrollet"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Shto një aplikacion"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Shto daljet"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupi"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 pajisje e zgjedhur"</string>
@@ -1023,14 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Përqindja e mbetur e baterisë: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Lidhe stilolapsin me një karikues"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria e stilolapsit në nivel të ulët"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Nuk mund të telefonosh nga ky profil"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Politika jote e punës të lejon të bësh telefonata vetëm nga profili i punës"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Kalo te profili i punës"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Mbyll"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5970655..00145d2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Аутоматска"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звука и вибрирања"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звука и вибрирања и приказује се у наставку одељка за конверзације"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да звони или вибрира у зависности од подешавања уређаја"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да звони или вибрира у зависности од подешавања уређаја. Конверзације из апликације <xliff:g id="APP_NAME">%1$s</xliff:g> подразумевано се приказују у облачићима."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Нека систем утврди да ли ово обавештење треба да емитује звук или да вибрира"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> Унапређено у Подразумевано"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> Деградирано у Нечујно"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Одаберите апликацију за додавање контрола"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# контрола је додата.}one{# контрола је додата.}few{# контроле су додате.}other{# контрола је додато.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Уклоњено"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Означено је као омиљено"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Означено је као омиљено, <xliff:g id="NUMBER">%d</xliff:g>. позиција"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Уклоњено је из омиљених"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Грешка. Пробајте поново"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Додај контроле"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Измени контроле"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Додајте излазе"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Изабран је 1 уређај"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Преостало је још<xliff:g id="PERCENTAGE">%s</xliff:g> батерије"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Повежите писаљку са пуњачем"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Низак ниво батерије писаљке"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Видео камера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Не можете да упућујете позиве са овог профила"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Смернице за посао вам омогућавају да телефонирате само са пословног профила"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Пређи на пословни профил"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Затвори"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 097af72..f1e0a6e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Automatiskt"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Inga ljud eller vibrationer"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Inga ljud eller vibrationer och visas längre ned bland konversationerna"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Kan ringa eller vibrera beroende på inställningarna på enheten"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Kan ringa eller vibrera beroende på inställningarna på enheten. Konversationer från <xliff:g id="APP_NAME">%1$s</xliff:g> visas i bubblor som standard."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Låt systemet avgöra om den här aviseringen ska låta eller vibrera"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Ändrad till Standard"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Ändrad till Tyst"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Välj en app om du vill lägga till snabbkontroller"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontroll har lagts till.}other{# kontroller har lagts till.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Har tagits bort"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Har lagts till som favorit"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Har lagts till som favorit, plats <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Har tagits bort från favoriter"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Fel, försök igen"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Lägg till snabbkontroller"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Redigera snabbkontroller"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Lägg till utgångar"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupp"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 enhet har valts"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> av batteriet återstår"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Anslut e-pennan till en laddare"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"E-pennans batterinivå är låg"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Det går inte att ringa från den här profilen"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Jobbprincipen tillåter endast att du ringer telefonsamtal från jobbprofilen"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Byt till jobbprofilen"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Stäng"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 94812c5..a126e7e 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatiki"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Hakuna sauti wala mtetemo"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Hakuna sauti wala mtetemo na huonekana upande wa chini katika sehemu ya mazungumzo"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Huenda ikalia au kutetema kulingana na mipangilio ya kifaa"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Huenda ikalia au kutetema kulingana na mipangilio ya kifaa. Mazungumzo kutoka kiputo cha <xliff:g id="APP_NAME">%1$s</xliff:g> kwa chaguomsingi."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Ruhusu mfumo ubainishe iwapo arifa hii inapaswa kutoa sauti au mtetemo"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Hali:</b> Imepandishwa Hadhi Kuwa Chaguomsingi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Imeshushwa Hadhi Kuwa Kimya"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Chagua programu ili uweke vidhibiti"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Umeweka kidhibiti #.}other{Umeweka vidhibiti #.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Kimeondolewa"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Kimewekwa kwenye vipendwa"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Kimewekwa kwenye vipendwa, nafasi ya <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Kimeondolewa kwenye vipendwa"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Hitilafu, jaribu tena"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Weka vidhibiti"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Badilisha vidhibiti"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Weka vifaa vya kutoa sauti"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Kikundi"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Umechagua kifaa 1"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Chaji ya betri imesalia <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Unganisha stylus yako kwenye chaja"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Chaji ya betri ya Stylus imepungua"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Kamera ya kuchukulia video"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Huwezi kupiga simu kutoka kwenye wasifu huu"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Sera ya mahali pako pa kazi inakuruhusu upige simu kutoka kwenye wasifu wa kazini pekee"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Tumia wasifu wa kazini"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Funga"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 1ca016a..a5528a1 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"தானியங்கு"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"ஒலி / அதிர்வு இல்லை"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"ஒலி / அதிர்வு இல்லாமல் உரையாடல் பிரிவின் கீழ்ப் பகுதியில் தோன்றும்"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"சாதன அமைப்புகளைப் பொறுத்து ஒலிக்கக்கூடும் அல்லது அதிர்வடையக்கூடும்"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"சாதன அமைப்புகளைப் பொறுத்து ஒலிக்கக்கூடும் அல்லது அதிர்வடையக்கூடும். இயல்பாக, <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸில் பெறப்படும் உரையாடல் அறிவிப்புகள் குமிழ்களாகத் தோன்றும்."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"இந்த அறிவிப்பு ஒலி எழுப்ப வேண்டுமா அதிர வேண்டுமா என்பதை சிஸ்டம் தீர்மானிக்கும்"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>நிலை:</b> இயல்புநிலைக்கு உயர்த்தி அமைக்கப்பட்டது"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>நிலை:</b> சைலன்ட் நிலைக்குக் குறைத்து அமைக்கப்பட்டது"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"கட்டுப்பாடுகளைச் சேர்க்க வேண்டிய ஆப்ஸைத் தேர்ந்தெடுங்கள்"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# கட்டுப்பாடு சேர்க்கப்பட்டது.}other{# கட்டுப்பாடுகள் சேர்க்கப்பட்டன.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"அகற்றப்பட்டது"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"பிடித்தவற்றில் சேர்க்கப்பட்டது"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"பிடித்தவற்றில் சேர்க்கப்பட்டது, நிலை <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"பிடித்தவற்றிலிருந்து நீக்கப்பட்டது"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"பிழை, மீண்டும் முயலவும்"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"கட்டுப்பாடுகளை மாற்றுதல்"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"அவுட்புட்களைச் சேர்த்தல்"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"குழு"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 சாதனம் தேர்ந்தெடுக்கப்பட்டுள்ளது"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> பேட்டரி மீதமுள்ளது"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"உங்கள் ஸ்டைலஸைச் சார்ஜருடன் இணையுங்கள்"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ஸ்டைலஸின் பேட்டரி குறைவாக உள்ளது"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"வீடியோ கேமரா"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"இந்தக் கணக்கிலிருந்து அழைக்க முடியாது"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"உங்கள் பணிக் கொள்கையின்படி நீங்கள் பணிக் கணக்கில் இருந்து மட்டுமே ஃபோன் அழைப்புகளைச் செய்ய முடியும்"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"பணிக் கணக்கிற்கு மாறு"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"மூடுக"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 766ebca..04b9d6d 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"కంట్రోల్స్ను యాడ్ చేయడానికి యాప్ను ఎంచుకోండి"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# కంట్రోల్ జోడించబడింది.}other{# కంట్రోల్స్ జోడించబడ్డాయి.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"తీసివేయబడింది"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ఇష్టమైనదిగా గుర్తు పెట్టబడింది"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"<xliff:g id="NUMBER">%d</xliff:g>వ స్థానంలో ఇష్టమైనదిగా గుర్తు పెట్టబడింది"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ఇష్టమైనదిగా పెట్టిన గుర్తు తీసివేయబడింది"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"ఎర్రర్, మళ్లీ ప్రయత్నించండి"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"కంట్రోల్స్ను జోడించండి"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"కంట్రోల్స్ను ఎడిట్ చేయండి"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"అవుట్పుట్లను జోడించండి"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"గ్రూప్"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 పరికరం ఎంచుకోబడింది"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"మీ వర్క్ పాలసీ, మిమ్మల్ని వర్క్ ప్రొఫైల్ నుండి మాత్రమే ఫోన్ కాల్స్ చేయడానికి అనుమతిస్తుంది"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"వర్క్ ప్రొఫైల్కు మారండి"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"మూసివేయండి"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 5a58355..28bb388 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -800,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"เลือกแอปเพื่อเพิ่มตัวควบคุม"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{เพิ่มตัวควบคุม # ตัวแล้ว}other{เพิ่มตัวควบคุม # ตัวแล้ว}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"นำออกแล้ว"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"เพิ่ม <xliff:g id="APPNAME">%s</xliff:g> ไหม"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"เมื่อเพิ่ม <xliff:g id="APPNAME">%s</xliff:g> คุณจะเพิ่มการควบคุมและเนื้อหาไปยังแผงนี้ได้ ในบางแอป คุณเลือกได้ว่าต้องการให้การควบคุมใดปรากฏขึ้นที่นี่"</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"ตั้งเป็นรายการโปรดแล้ว"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"ตั้งเป็นรายการโปรดแล้ว โดยอยู่ลำดับที่ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"นำออกจากรายการโปรดแล้ว"</string>
@@ -866,6 +868,7 @@
<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_add_another_app" msgid="8661172304650786705">"เพิ่มแอป"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"เพิ่มเอาต์พุต"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"กลุ่ม"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"เลือกอุปกรณ์ไว้ 1 รายการ"</string>
@@ -1026,4 +1029,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"นโยบายการทำงานอนุญาตให้คุณโทรออกได้จากโปรไฟล์งานเท่านั้น"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"สลับไปใช้โปรไฟล์งาน"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"ปิด"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index b07ad7b..7387289 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Awtomatiko"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Walang tunog o pag-vibrate"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Walang tunog o pag-vibrate at lumalabas nang mas mababa sa seksyon ng pag-uusap"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Puwedeng mag-ring o mag-vibrate batay sa mga setting ng device"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Puwedeng mag-ring o mag-vibrate batay sa mga setting ng device. Mga pag-uusap mula sa <xliff:g id="APP_NAME">%1$s</xliff:g> bubble bilang default."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Ipatukoy sa system kung dapat gumawa ng tunog o pag-vibrate ang notification na ito"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Status:</b> Na-promote sa Default"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Status:</b> Na-demote sa Naka-silent"</string>
@@ -802,6 +800,8 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Pumili ng app para magdagdag ng mga kontrol"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Nagdagdag ng # kontrol.}one{Nagdagdag ng # kontrol.}other{Nagdagdag ng # na kontrol.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Inalis"</string>
+ <string name="controls_panel_authorization_title" msgid="267429338785864842">"Idagdag ang <xliff:g id="APPNAME">%s</xliff:g>?"</string>
+ <string name="controls_panel_authorization" msgid="4540047176861801815">"Kapag idinagdag mo ang <xliff:g id="APPNAME">%s</xliff:g>, puwede itong magdagdag ng mga kontrol at content sa panel na ito. Sa ilang app, puwede mong piliin kung aling mga kontrol ang lalabas dito."</string>
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Ginawang paborito"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Ginawang paborito, posisyon <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Inalis sa paborito"</string>
@@ -868,6 +868,7 @@
<string name="controls_error_failed" msgid="960228639198558525">"Nagka-error, subukan ulit"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Magdagdag ng mga kontrol"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Mag-edit ng mga kontrol"</string>
+ <string name="controls_menu_add_another_app" msgid="8661172304650786705">"Magdagdag ng app"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Magdagdag ng mga output"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grupo"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 device ang napili"</string>
@@ -1023,14 +1024,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> baterya na lang ang natitira"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ikonekta sa charger ang iyong stylus"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Paubos na ang baterya ng stylus"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Video camera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Hindi puwedeng tumawag mula sa profile na ito"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Pinapayagan ka ng iyong patakaran sa trabaho na tumawag lang mula sa profile sa trabaho"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Lumipat sa profile sa trabaho"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Isara"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 07cec1a..3351089 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Otomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Sessiz veya titreşim yok"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ses veya titreşim yok, görüşme bölümünün altında görünür"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Cihaz ayarlarına bağlı olarak zili çalabilir veya titreyebilir"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Cihaz ayarlarına bağlı olarak zili çalabilir veya titreyebilir <xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamadan görüşmeler varsayılan olarak baloncukla gösterilir."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Bu bildirimin ses çıkarması veya titreşmesi gerekip gerekmediğine sistem karar versin"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Durum:</b> Varsayılana yükseltildi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Durum:</b> Sessize Düşürüldü"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Denetim eklemek için uygulama seçin"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# kontrol eklendi.}other{# kontrol eklendi.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Kaldırıldı"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Favoriler listesine eklendi"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Favorilere eklendi, konum: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Favorilerden kaldırıldı"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Hata, yeniden deneyin"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Denetim ekle"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Denetimleri düzenle"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Çıkışlar ekleyin"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Grup"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 cihaz seçildi"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> pil kaldı"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ekran kaleminizi bir şarj cihazına bağlayın"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ekran kaleminin pil seviyesi düşük"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Video kamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Bu profilden telefon araması yapılamıyor"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"İşletme politikanız yalnızca iş profilinden telefon araması yapmanıza izin veriyor"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"İş profiline geç"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Kapat"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 804d2c1..0a93ec6 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматично"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звуку чи вібрації"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звуку чи вібрації, з\'являється нижче в розділі розмов"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Дзвінок або вібрація залежно від налаштувань пристрою"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може дзвонити або вібрувати залежно від налаштувань пристрою. Показує спливаючі розмови з додатка <xliff:g id="APP_NAME">%1$s</xliff:g> за умовчанням."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Дозволити системі визначати, чи має сповіщення супроводжуватися звуком або вібрацією"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус</b>: підвищено до \"За умовчанням\""</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус</b>: знижено до \"Без звуку\""</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Виберіть, для якого додатка налаштувати елементи керування"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Додано # елемент керування.}one{Додано # елемент керування.}few{Додано # елементи керування.}many{Додано # елементів керування.}other{Додано # елемента керування.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Вилучено"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Додано у вибране"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Додано у вибране, позиція <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Видалено з вибраного"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Помилка. Спробуйте знову"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Додати елементи керування"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Змінити елементи керування"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Додати пристрої виводу"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Група"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Вибрано 1 пристрій"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Заряд акумулятора: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Підключіть стилус до зарядного пристрою"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Низький заряд акумулятора стилуса"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Відеокамера"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Неможливо телефонувати з цього профілю"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Відповідно до правил організації ви можете телефонувати лише з робочого профілю"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Перейти в робочий профіль"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Закрити"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index dde5323..1b7e40f 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"کنٹرولز شامل کرنے کے لیے ایپ منتخب کریں"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# کنٹرول کو شامل کیا گیا۔}other{# کنٹرولز کو شامل کیا گیا۔}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"ہٹا دیا گیا"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"پسند کردہ"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"پسند کردہ، پوزیشن <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"ناپسند کردہ"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"خرابی، دوبارہ کوشش کریں"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"کنٹرولز شامل کریں"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"کنٹرولز میں ترمیم کریں"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"آؤٹ پٹس شامل کریں"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"گروپ"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 آلہ منتخب کیا گیا"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"آپ کے کام سے متعلق پالیسی آپ کو صرف دفتری پروفائل سے فون کالز کرنے کی اجازت دیتی ہے"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"دفتری پروفائل پر سوئچ کریں"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"بند کریں"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 5b60765..21b088e 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Avtomatik"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Tovush yoki tebranishsiz"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tovush yoki tebranishsiz hamda suhbatlar ruknining pastida chiqadi"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Qurilma sozlamalari asosida jiringlashi yoki tebranishi mumkin"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Qurilma sozlamalari asosida jiringlashi yoki tebranishi mumkin. <xliff:g id="APP_NAME">%1$s</xliff:g> suhbatlari standart holatda bulutcha shaklida chiqadi."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Bu bildirishnoma jiringlashi yoki tebranishini hal qilsin"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Holati:</b> Birlamchi darajaga chiqarildi"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Holati:</b> Sokin darajaga tushirildi"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Boshqaruv elementlarini kiritish uchun ilovani tanlang"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{# ta boshqaruv elementi kiritildi.}other{# ta boshqaruv elementi kiritildi.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Olib tashlandi"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Saralanganlarga kiritilgan"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Saralanganlarga kiritilgan, <xliff:g id="NUMBER">%d</xliff:g>-joy"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Saralanganlardan olib tashlangan"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Xato, qayta urining"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Element kiritish"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Elementlarni tahrirlash"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Chiquvchi qurilmani kiritish"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Guruh"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"1 ta qurilma tanlandi"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Batareya quvvati: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Stilusni quvvat manbaiga ulang"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stilus batareyasi kam"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Bu profildan chaqiruv qilish imkonsiz"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Ishga oid siyosatingiz faqat ish profilidan telefon chaqiruvlarini amalga oshirish imkonini beradi"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Ish profiliga almashish"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Yopish"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d7ce218..016c834 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Tự động"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Không phát âm thanh hoặc rung"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Không phát âm thanh hoặc rung và xuất hiện phía dưới trong phần cuộc trò chuyện"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Có thể đổ chuông hoặc rung tuỳ theo chế độ cài đặt trên thiết bị"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Có thể đổ chuông hoặc rung tuỳ theo chế độ cài đặt trên thiết bị. Theo mặc định, các cuộc trò chuyện từ <xliff:g id="APP_NAME">%1$s</xliff:g> sẽ hiển thị dưới dạng bong bóng."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Cho phép hệ thống quyết định xem thông báo này phát âm thanh hay rung"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Trạng thái:</b> Đã thay đổi thành Mặc định"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Trạng thái:</b> Đã thay đổi thành Im lặng"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Chọn ứng dụng để thêm các tùy chọn điều khiển"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{Đã thêm # chế độ điều khiển.}other{Đã thêm # chế độ điều khiển.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Đã xóa"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Được yêu thích"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Được yêu thích, vị trí số <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Không được yêu thích"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Lỗi, hãy thử lại"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Thêm các tùy chọn điều khiển"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Chỉnh sửa tùy chọn điều khiển"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Thêm thiết bị đầu ra"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Nhóm"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"Đã chọn 1 thiết bị"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"Còn <xliff:g id="PERCENTAGE">%s</xliff:g> pin"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hãy kết nối bút cảm ứng với bộ sạc"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bút cảm ứng bị yếu pin"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Máy quay video"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Không thể gọi điện từ hồ sơ này"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Chính sách của nơi làm việc chỉ cho phép bạn gọi điện thoại từ hồ sơ công việc"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Chuyển sang hồ sơ công việc"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Đóng"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index a94c411..eff645e 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"自动"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"不发出提示音,也不振动"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"不发出提示音,也不振动;显示在对话部分的靠下位置"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"可能会响铃或振动,取决于设备设置"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"可能会响铃或振动,取决于设备设置。默认情况下,来自<xliff:g id="APP_NAME">%1$s</xliff:g>的对话会以对话泡的形式显示。"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"让系统决定是否应让设备在收到此通知时发出提示音或振动"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>状态</b>:已提升为“默认”"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>状态</b>:已降低为“静音”"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"选择要添加控制器的应用"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已添加 # 个控件。}other{已添加 # 个控件。}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"已移除"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"已收藏"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"已收藏,位置:<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"已取消收藏"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"出现错误,请重试"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"添加控制器"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"修改控制器"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"添加输出设备"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"群组"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已选择 1 个设备"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"电池还剩 <xliff:g id="PERCENTAGE">%s</xliff:g> 的电量"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"请将触控笔连接充电器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"触控笔电池电量低"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"摄像机"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"无法通过这份资料拨打电话"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"根据您的工作政策,您只能通过工作资料拨打电话"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"切换到工作资料"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"关闭"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index c0fb5b1..1f51da8 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -532,8 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"自動"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"無音效或震動"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"無音效或震動,並在對話部分的較低位置顯示"</string>
- <string name="notification_channel_summary_default" msgid="777294388712200605">"根據裝置的設定響鈴或震動"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"根據裝置的設定響鈴或震動。根據預設,來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會以對話框形式顯示。"</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"可能會根據裝置設定發出鈴聲或震動"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"可能會根據裝置設定發出鈴聲或震動。根據預設,來自 <xliff:g id="APP_NAME">%1$s</xliff:g> 的對話會以對話氣泡顯示。"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"由系統判斷是否要讓此通知發出音效或震動"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>狀態:</b>已提升為預設"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>狀態:</b>已降低為靜音"</string>
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"選擇要新增控制項的應用程式"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已新增 # 個控制項。}other{已新增 # 個控制項。}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"已移除"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"已加入收藏"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"已加入至收藏位置 <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"已取消收藏"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請重試"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"新增輸出裝置"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"群組"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
@@ -1022,8 +1028,10 @@
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆連接充電器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電量不足"</string>
<string name="video_camera" msgid="7654002575156149298">"攝影機"</string>
- <string name="call_from_work_profile_title" msgid="6991157106804289643">"無法透過這個資料夾撥打電話"</string>
- <string name="call_from_work_profile_text" msgid="3458704745640229638">"貴公司政策僅允許透過工作資料夾撥打電話"</string>
- <string name="call_from_work_profile_action" msgid="2937701298133010724">"切換至工作資料夾"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"無法透過此設定檔撥打電話"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"您的公司政策只允許透過工作設定檔撥打電話"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"切換至工作設定檔"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"關閉"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 48dc5bf..6ac7992 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -800,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{已新增 # 個控制項。}other{已新增 # 個控制項。}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"已移除"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"已加入收藏"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"已加入收藏,位置 <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"從收藏中移除"</string>
@@ -866,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請再試一次"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"新增輸出裝置"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"群組"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"已選取 1 部裝置"</string>
@@ -1026,4 +1032,6 @@
<string name="call_from_work_profile_text" msgid="3458704745640229638">"貴公司政策僅允許透過工作資料夾撥打電話"</string>
<string name="call_from_work_profile_action" msgid="2937701298133010724">"切換至工作資料夾"</string>
<string name="call_from_work_profile_close" msgid="7927067108901068098">"關閉"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 88c00a8..6577837 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -532,10 +532,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Okuzenzekelayo"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Awukho umsindo noma ukudlidliza"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Awukho umsindo noma ukudlidliza futhi ivela ngezansi esigabeni sengxoxo"</string>
- <!-- no translation found for notification_channel_summary_default (777294388712200605) -->
- <skip />
- <!-- no translation found for notification_channel_summary_default_with_bubbles (3482483084451555344) -->
- <skip />
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Ingase ikhale noma idlidlize ngokusekelwe kumasethingi edivayisi"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Ingase ikhale noma idlidlize kuya ngamasethingi wedivayisi. Izingxoxo ezivela ku-<xliff:g id="APP_NAME">%1$s</xliff:g> ziba yibhamuza ngokuzenzakalela."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Vumela isistimu inqume uma lesi saziso kufanele senze umsindo noma sidlidlize"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Isimo:</b> Siphromothelwe Kokuzenzakalelayo"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Isimo:</b> Sehliselwe Kokuthulile"</string>
@@ -802,6 +800,10 @@
<string name="controls_providers_title" msgid="6879775889857085056">"Khetha uhlelo lokusebenza ukwengeza izilawuli"</string>
<string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{ulawulo olu-# olwengeziwe.}one{ukulawulwa okungu-# okwengeziwe.}other{ukulawulwa okungu-# okwengeziwe.}}"</string>
<string name="controls_removed" msgid="3731789252222856959">"Isusiwe"</string>
+ <!-- no translation found for controls_panel_authorization_title (267429338785864842) -->
+ <skip />
+ <!-- no translation found for controls_panel_authorization (4540047176861801815) -->
+ <skip />
<string name="accessibility_control_favorite" msgid="8694362691985545985">"Kwenziwe intandokazi"</string>
<string name="accessibility_control_favorite_position" msgid="54220258048929221">"Kwenziwe intandokazi, isimo esiyi-<xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="accessibility_control_not_favorite" msgid="1291760269563092359">"Akwenziwanga intandokazi"</string>
@@ -868,6 +870,8 @@
<string name="controls_error_failed" msgid="960228639198558525">"Iphutha, zama futhi"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Engeza Izilawuli"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Hlela izilawuli"</string>
+ <!-- no translation found for controls_menu_add_another_app (8661172304650786705) -->
+ <skip />
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Engeza okukhiphayo"</string>
<string name="media_output_dialog_group" msgid="5571251347877452212">"Iqembu"</string>
<string name="media_output_dialog_single_device" msgid="3102758980643351058">"idivayisi ekhethiwe e-1"</string>
@@ -1023,14 +1027,11 @@
<string name="stylus_battery_low_percentage" msgid="1620068112350141558">"<xliff:g id="PERCENTAGE">%s</xliff:g> ibhethri elisele"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Xhuma i-stylus yakho kushaja"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ibhethri le-stylus liphansi"</string>
- <!-- no translation found for video_camera (7654002575156149298) -->
- <skip />
- <!-- no translation found for call_from_work_profile_title (6991157106804289643) -->
- <skip />
- <!-- no translation found for call_from_work_profile_text (3458704745640229638) -->
- <skip />
- <!-- no translation found for call_from_work_profile_action (2937701298133010724) -->
- <skip />
- <!-- no translation found for call_from_work_profile_close (7927067108901068098) -->
+ <string name="video_camera" msgid="7654002575156149298">"Ikhamera yevidiyo"</string>
+ <string name="call_from_work_profile_title" msgid="6991157106804289643">"Ayikwazi ukufonela le phrofayela"</string>
+ <string name="call_from_work_profile_text" msgid="3458704745640229638">"Inqubomgomo yakho yomsebenzi ikuvumela ukuthi wenze amakholi wefoni kuphela ngephrofayela yomsebenzi"</string>
+ <string name="call_from_work_profile_action" msgid="2937701298133010724">"Shintshela kuphrofayela yomsebenzi"</string>
+ <string name="call_from_work_profile_close" msgid="7927067108901068098">"Vala"</string>
+ <!-- no translation found for lock_screen_settings (9197175446592718435) -->
<skip />
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index e8a5e7e..1826c00 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -824,4 +824,8 @@
<item>bottom_end:wallet</item>
</string-array>
+ <!-- Package name for the app that implements the wallpaper picker. -->
+ <string name="config_wallpaperPickerPackage" translatable="false">
+ com.android.wallpaper
+ </string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1ef0206..f3bef92 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -337,7 +337,7 @@
<!-- Used for both start and bottom margin of the preview, relative to the action container -->
<dimen name="overlay_preview_container_margin">8dp</dimen>
<dimen name="overlay_action_container_margin_horizontal">8dp</dimen>
- <dimen name="overlay_action_container_margin_bottom">4dp</dimen>
+ <dimen name="overlay_action_container_margin_bottom">6dp</dimen>
<dimen name="overlay_bg_protection_height">242dp</dimen>
<dimen name="overlay_action_container_corner_radius">18dp</dimen>
<dimen name="overlay_action_container_padding_vertical">4dp</dimen>
@@ -1648,4 +1648,10 @@
<dimen name="rear_display_animation_height">200dp</dimen>
<dimen name="rear_display_title_top_padding">24dp</dimen>
<dimen name="rear_display_title_bottom_padding">16dp</dimen>
+
+ <!--
+ Vertical distance between the pointer and the popup menu that shows up on the lock screen when
+ it is long-pressed.
+ -->
+ <dimen name="keyguard_long_press_settings_popup_vertical_offset">96dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8dcd3b0..5607c63 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2428,6 +2428,8 @@
<string name="media_output_group_title_speakers_and_displays">Speakers & Displays</string>
<!-- Title for Suggested Devices group. [CHAR LIMIT=NONE] -->
<string name="media_output_group_title_suggested_device">Suggested Devices</string>
+ <!-- Sub status indicates device need premium account. [CHAR LIMIT=NONE] -->
+ <string name="media_output_status_require_premium">Requires premium account</string>
<!-- Media Output Broadcast Dialog -->
<!-- Title for Broadcast First Notify Dialog [CHAR LIMIT=60] -->
@@ -2808,4 +2810,13 @@
<!-- Label for the close button on switch to work profile dialog. Switch to work profile dialog guide users to make call from work
profile dialer app as it's not possible to make call from current profile due to an admin policy.[CHAR LIMIT=60] -->
<string name="call_from_work_profile_close">Close</string>
+
+ <!--
+ Label for a menu item in a menu that is shown when the user wishes to configure the lock screen.
+ Clicking on this menu item takes the user to a screen where they can modify the settings of the
+ lock screen.
+
+ [CHAR LIMIT=32]
+ -->
+ <string name="lock_screen_settings">Lock screen settings</string>
</resources>
diff --git a/packages/SystemUI/scripts/token_alignment/.eslintrc.json b/packages/SystemUI/scripts/token_alignment/.eslintrc.json
new file mode 100644
index 0000000..69dc00e
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/.eslintrc.json
@@ -0,0 +1,31 @@
+{
+ "env": {
+ "es2021": true,
+ "node": true
+ },
+ "parserOptions": {
+ "ecmaVersion": "latest",
+ "sourceType": "module"
+ },
+ "plugins": ["prettier", "@typescript-eslint", "eslint-plugin-simple-import-sort", "import"],
+ "extends": ["prettier", "eslint:recommended", "plugin:@typescript-eslint/recommended"],
+ "rules": {
+ "prettier/prettier": ["error"],
+ "no-unused-vars": "off",
+ "@typescript-eslint/no-unused-vars": [
+ "warn",
+ {
+ "argsIgnorePattern": "^_",
+ "varsIgnorePattern": "^_",
+ "caughtErrorsIgnorePattern": "^_"
+ }
+ ],
+ "no-multiple-empty-lines": ["error", { "max": 2 }],
+ "no-multi-spaces": "error",
+ "simple-import-sort/imports": "error",
+ "simple-import-sort/exports": "error",
+ "import/first": "error",
+ "import/newline-after-import": "error",
+ "import/no-duplicates": "error"
+ }
+}
diff --git a/packages/SystemUI/scripts/token_alignment/.gitignore b/packages/SystemUI/scripts/token_alignment/.gitignore
new file mode 100644
index 0000000..96ce14f
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/.gitignore
@@ -0,0 +1,2 @@
+vscode
+node_modules
\ No newline at end of file
diff --git a/packages/SystemUI/scripts/token_alignment/.prettierrc b/packages/SystemUI/scripts/token_alignment/.prettierrc
new file mode 100644
index 0000000..20f02f9
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/.prettierrc
@@ -0,0 +1,9 @@
+{
+ "tabWidth": 4,
+ "printWidth": 100,
+ "semi": true,
+ "singleQuote": true,
+ "bracketSameLine": true,
+ "bracketSpacing": true,
+ "arrowParens": "always"
+}
\ No newline at end of file
diff --git a/packages/SystemUI/scripts/token_alignment/helpers/DOMFuncs.ts b/packages/SystemUI/scripts/token_alignment/helpers/DOMFuncs.ts
new file mode 100644
index 0000000..80e075c
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/helpers/DOMFuncs.ts
@@ -0,0 +1,297 @@
+// Copyright 2022 Google LLC
+
+// 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.
+
+type IElementComment =
+ | { commentNode: undefined; textContent: undefined; hidden: undefined }
+ | { commentNode: Node; textContent: string; hidden: boolean };
+
+interface ITag {
+ attrs?: Record<string, string | number>;
+ tagName: string;
+}
+
+export interface INewTag extends ITag {
+ content?: string | number;
+ comment?: string;
+}
+
+export type IUpdateTag = Partial<Omit<INewTag, 'tagName'>>;
+
+export default class DOM {
+ static addEntry(containerElement: Element, tagOptions: INewTag) {
+ const doc = containerElement.ownerDocument;
+ const exists = this.alreadyHasEntry(containerElement, tagOptions);
+
+ if (exists) {
+ console.log('Ignored adding entry already available: ', exists.outerHTML);
+ return;
+ }
+
+ let insertPoint: Node | null = containerElement.lastElementChild; //.childNodes[containerElement.childNodes.length - 1];
+
+ if (!insertPoint) {
+ console.log('Ignored adding entry in empity parent: ', containerElement.outerHTML);
+ return;
+ }
+
+ const { attrs, comment, content, tagName } = tagOptions;
+
+ if (comment) {
+ const commentNode = doc.createComment(comment);
+ this.insertAfterIdented(commentNode, insertPoint);
+ insertPoint = commentNode;
+ }
+
+ const newEl = doc.createElement(tagName);
+ if (content) newEl.innerHTML = content.toString();
+ if (attrs)
+ Object.entries(attrs).forEach(([attr, value]) =>
+ newEl.setAttribute(attr, value.toString())
+ );
+ this.insertAfterIdented(newEl, insertPoint);
+
+ return true;
+ }
+
+ static insertBeforeIndented(newNode: Node, referenceNode: Node) {
+ const paddingNode = referenceNode.previousSibling;
+ const ownerDoc = referenceNode.ownerDocument;
+ const containerNode = referenceNode.parentNode;
+
+ if (!paddingNode || !ownerDoc || !containerNode) return;
+
+ const currentPadding = paddingNode.textContent || '';
+ const textNode = referenceNode.ownerDocument.createTextNode(currentPadding);
+
+ containerNode.insertBefore(newNode, referenceNode);
+ containerNode.insertBefore(textNode, newNode);
+ }
+
+ static insertAfterIdented(newNode: Node, referenceNode: Node) {
+ const paddingNode = referenceNode.previousSibling;
+ const ownerDoc = referenceNode.ownerDocument;
+ const containerNode = referenceNode.parentNode;
+
+ if (!paddingNode || !ownerDoc || !containerNode) return;
+
+ const currentPadding = paddingNode.textContent || '';
+ const textNode = ownerDoc.createTextNode(currentPadding);
+
+ containerNode.insertBefore(newNode, referenceNode.nextSibling);
+ containerNode.insertBefore(textNode, newNode);
+ }
+
+ static getElementComment(el: Element): IElementComment {
+ const commentNode = el.previousSibling?.previousSibling;
+
+ const out = { commentNode: undefined, textContent: undefined, hidden: undefined };
+
+ if (!commentNode) return out;
+
+ const textContent = commentNode.textContent || '';
+ const hidden = textContent.substring(textContent.length - 6) == '@hide ';
+
+ if (!(commentNode && commentNode.nodeName == '#comment')) return out;
+
+ return { commentNode, textContent, hidden: hidden };
+ }
+
+ static duplicateEntryWithChange(
+ templateElement: Element,
+ options: Omit<IUpdateTag, 'content'>
+ ) {
+ const exists = this.futureEntryAlreadyExist(templateElement, options);
+ if (exists) {
+ console.log('Ignored duplicating entry already available: ', exists.outerHTML);
+ return;
+ }
+
+ const { commentNode } = this.getElementComment(templateElement);
+ let insertPoint: Node = templateElement;
+
+ if (commentNode) {
+ const newComment = commentNode.cloneNode();
+ this.insertAfterIdented(newComment, insertPoint);
+ insertPoint = newComment;
+ }
+
+ const newEl = templateElement.cloneNode(true) as Element;
+ this.insertAfterIdented(newEl, insertPoint);
+
+ this.updateElement(newEl, options);
+ return true;
+ }
+
+ static replaceStringInAttributeValueOnQueried(
+ root: Element,
+ query: string,
+ attrArray: string[],
+ replaceMap: Map<string, string>
+ ): boolean {
+ let updated = false;
+ const queried = [...Array.from(root.querySelectorAll(query)), root];
+
+ queried.forEach((el) => {
+ attrArray.forEach((attr) => {
+ if (el.hasAttribute(attr)) {
+ const currentAttrValue = el.getAttribute(attr);
+
+ if (!currentAttrValue) return;
+
+ [...replaceMap.entries()].some(([oldStr, newStr]) => {
+ if (
+ currentAttrValue.length >= oldStr.length &&
+ currentAttrValue.indexOf(oldStr) ==
+ currentAttrValue.length - oldStr.length
+ ) {
+ el.setAttribute(attr, currentAttrValue.replace(oldStr, newStr));
+ updated = true;
+ return true;
+ }
+ return false;
+ });
+ }
+ });
+ });
+
+ return updated;
+ }
+
+ static updateElement(el: Element, updateOptions: IUpdateTag) {
+ const exists = this.futureEntryAlreadyExist(el, updateOptions);
+ if (exists) {
+ console.log('Ignored updating entry already available: ', exists.outerHTML);
+ return;
+ }
+
+ const { comment, attrs, content } = updateOptions;
+
+ if (comment) {
+ const { commentNode } = this.getElementComment(el);
+ if (commentNode) {
+ commentNode.textContent = comment;
+ }
+ }
+
+ if (attrs) {
+ for (const attr in attrs) {
+ const value = attrs[attr];
+
+ if (value != undefined) {
+ el.setAttribute(attr, `${value}`);
+ } else {
+ el.removeAttribute(attr);
+ }
+ }
+ }
+
+ if (content != undefined) {
+ el.innerHTML = `${content}`;
+ }
+
+ return true;
+ }
+
+ static elementToOptions(el: Element): ITag {
+ return {
+ attrs: this.getAllElementAttributes(el),
+ tagName: el.tagName,
+ };
+ }
+
+ static getAllElementAttributes(el: Element): Record<string, string> {
+ return el
+ .getAttributeNames()
+ .reduce(
+ (acc, attr) => ({ ...acc, [attr]: el.getAttribute(attr) || '' }),
+ {} as Record<string, string>
+ );
+ }
+
+ static futureEntryAlreadyExist(el: Element, updateOptions: IUpdateTag) {
+ const currentElOptions = this.elementToOptions(el);
+
+ if (!el.parentElement) {
+ console.log('Checked el has no parent');
+ process.exit();
+ }
+
+ return this.alreadyHasEntry(el.parentElement, {
+ ...currentElOptions,
+ ...updateOptions,
+ attrs: { ...currentElOptions.attrs, ...updateOptions.attrs },
+ });
+ }
+
+ static alreadyHasEntry(
+ containerElement: Element,
+ { attrs, tagName }: Pick<INewTag, 'attrs' | 'tagName'>
+ ) {
+ const qAttrs = attrs
+ ? Object.entries(attrs)
+ .map(([a, v]) => `[${a}="${v}"]`)
+ .join('')
+ : '';
+
+ return containerElement.querySelector(tagName + qAttrs);
+ }
+
+ static replaceContentTextOnQueried(
+ root: Element,
+ query: string,
+ replacePairs: Array<[string, string]>
+ ) {
+ let updated = false;
+ let queried = Array.from(root.querySelectorAll(query));
+
+ if (queried.length == 0) queried = [...Array.from(root.querySelectorAll(query)), root];
+
+ queried.forEach((el) => {
+ replacePairs.forEach(([oldStr, newStr]) => {
+ if (el.innerHTML == oldStr) {
+ el.innerHTML = newStr;
+ updated = true;
+ }
+ });
+ });
+
+ return updated;
+ }
+
+ static XMLDocToString(doc: XMLDocument) {
+ let str = '';
+
+ doc.childNodes.forEach((node) => {
+ switch (node.nodeType) {
+ case 8: // comment
+ str += `<!--${node.nodeValue}-->\n`;
+ break;
+
+ case 3: // text
+ str += node.textContent;
+ break;
+
+ case 1: // element
+ str += (node as Element).outerHTML;
+ break;
+
+ default:
+ console.log('Unhandled node type: ' + node.nodeType);
+ break;
+ }
+ });
+
+ return str;
+ }
+}
diff --git a/packages/SystemUI/scripts/token_alignment/helpers/FileIO.ts b/packages/SystemUI/scripts/token_alignment/helpers/FileIO.ts
new file mode 100644
index 0000000..359e3ab
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/helpers/FileIO.ts
@@ -0,0 +1,112 @@
+// Copyright 2022 Google LLC
+
+// 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.import { exec } from 'child_process';
+
+import { exec } from 'child_process';
+import { parse } from 'csv-parse';
+import { promises as fs } from 'fs';
+import jsdom from 'jsdom';
+
+const DOMParser = new jsdom.JSDOM('').window.DOMParser as typeof window.DOMParser;
+
+type TFileList = string[];
+
+export type TCSVRecord = Array<string | boolean | number>;
+
+class _FileIO {
+ public parser = new DOMParser();
+ public saved: string[] = [];
+
+ public loadXML = async (path: string): Promise<XMLDocument> => {
+ try {
+ const src = await this.loadFileAsText(path);
+ return this.parser.parseFromString(src, 'text/xml') as XMLDocument;
+ } catch (error) {
+ console.log(`Failed to parse XML file '${path}'.`, error);
+ process.exit();
+ }
+ };
+
+ public loadFileAsText = async (path: string): Promise<string> => {
+ try {
+ return await fs.readFile(path, { encoding: 'utf8' });
+ } catch (error) {
+ console.log(`Failed to read file '${path}'.`, error);
+ process.exit();
+ }
+ };
+
+ public saveFile = async (data: string, path: string) => {
+ try {
+ await fs.writeFile(path, data, { encoding: 'utf8' });
+ this.saved.push(path);
+ } catch (error) {
+ console.log(error);
+ console.log(`Failed to write file '${path}'.`);
+ process.exit();
+ }
+ };
+
+ public loadFileList = async (path: string): Promise<TFileList> => {
+ const src = await this.loadFileAsText(path);
+
+ try {
+ return JSON.parse(src) as TFileList;
+ } catch (error) {
+ console.log(error);
+ console.log(`Failed to parse JSON file '${path}'.`);
+ process.exit();
+ }
+ };
+
+ public loadCSV = (path: string): Promise<Array<TCSVRecord>> => {
+ return new Promise((resolve, reject) => {
+ this.loadFileAsText(path).then((src) => {
+ parse(
+ src,
+ {
+ delimiter: ' ',
+ },
+ (err, records) => {
+ if (err) {
+ reject(err);
+ return;
+ }
+
+ resolve(records);
+ }
+ );
+ });
+ });
+ };
+
+ formatSaved = () => {
+ const cmd = `idea format ${this.saved.join(' ')}`;
+
+ exec(cmd, (error, out, stderr) => {
+ if (error) {
+ console.log(error.message);
+ return;
+ }
+
+ if (stderr) {
+ console.log(stderr);
+ return;
+ }
+
+ console.log(out);
+ });
+ };
+}
+
+export const FileIO = new _FileIO();
diff --git a/packages/SystemUI/scripts/token_alignment/helpers/migrationList.ts b/packages/SystemUI/scripts/token_alignment/helpers/migrationList.ts
new file mode 100644
index 0000000..8d50644
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/helpers/migrationList.ts
@@ -0,0 +1,70 @@
+// Copyright 2022 Google LLC
+
+// 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.import { exec } from 'child_process';
+
+import { FileIO, TCSVRecord } from './FileIO';
+import ProcessArgs from './processArgs';
+
+interface IInputMigItem {
+ migrationToken: string;
+ materialToken: string;
+ newDefaultValue?: string;
+ newComment?: string;
+}
+
+interface IAditionalKeys {
+ step: ('update' | 'duplicate' | 'add' | 'ignore')[];
+ isHidden: boolean;
+ replaceToken: string;
+}
+
+export type IMigItem = Omit<IInputMigItem, 'materialToken' | 'migrationToken'> & IAditionalKeys;
+
+export type IMigrationMap = Map<string, IMigItem>;
+
+function isMigrationRecord(record: TCSVRecord): record is string[] {
+ return !record.some((value) => typeof value != 'string') || record.length != 5;
+}
+
+export const loadMIgrationList = async function (): Promise<IMigrationMap> {
+ const out: IMigrationMap = new Map();
+ const csv = await FileIO.loadCSV('resources/migrationList.csv');
+
+ csv.forEach((record, i) => {
+ if (i == 0) return; // header
+
+ if (typeof record[0] != 'string') return;
+
+ if (!isMigrationRecord(record)) {
+ console.log(`Failed to validade CSV record as string[5].`, record);
+ process.exit();
+ }
+
+ const [originalToken, materialToken, newDefaultValue, newComment, migrationToken] = record;
+
+ if (out.has(originalToken)) {
+ console.log('Duplicated entry on Migration CSV file: ', originalToken);
+ return;
+ }
+
+ out.set(originalToken, {
+ replaceToken: ProcessArgs.isDebug ? migrationToken : materialToken,
+ ...(!!newDefaultValue && { newDefaultValue }),
+ ...(!!newComment && { newComment }),
+ step: [],
+ isHidden: false,
+ });
+ });
+
+ return new Map([...out].sort((a, b) => b[0].length - a[0].length));
+};
diff --git a/packages/SystemUI/scripts/token_alignment/helpers/processArgs.ts b/packages/SystemUI/scripts/token_alignment/helpers/processArgs.ts
new file mode 100644
index 0000000..be0e232
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/helpers/processArgs.ts
@@ -0,0 +1,21 @@
+// Copyright 2022 Google LLC
+
+// 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.import { exec } from 'child_process';
+
+const myArgs = process.argv.slice(2);
+
+const ProcessArgs = {
+ isDebug: myArgs.includes('debug'),
+};
+
+export default ProcessArgs;
diff --git a/packages/SystemUI/scripts/token_alignment/helpers/processXML.ts b/packages/SystemUI/scripts/token_alignment/helpers/processXML.ts
new file mode 100644
index 0000000..368d4cb
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/helpers/processXML.ts
@@ -0,0 +1,102 @@
+// Copyright 2022 Google LLC
+
+// 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.import { exec } from 'child_process';
+
+import DOM, { INewTag, IUpdateTag } from './DOMFuncs';
+import { FileIO } from './FileIO';
+import { IMigItem, IMigrationMap } from './migrationList';
+
+export type TResultExistingEval = ['update' | 'duplicate', IUpdateTag] | void;
+export type TResultMissingEval = INewTag | void;
+
+interface IProcessXML {
+ attr?: string;
+ containerQuery?: string;
+ evalExistingEntry?: TEvalExistingEntry;
+ evalMissingEntry?: TEvalMissingEntry;
+ hidable?: boolean;
+ path: string;
+ step: number;
+ tagName: string;
+}
+
+export type TEvalExistingEntry = (
+ attrname: string,
+ migItem: IMigItem,
+ qItem: Element
+) => TResultExistingEval;
+
+export type TEvalMissingEntry = (originalToken: string, migItem: IMigItem) => TResultMissingEval;
+
+export async function processQueriedEntries(
+ migrationMap: IMigrationMap,
+ {
+ attr = 'name',
+ containerQuery = '*',
+ evalExistingEntry,
+ path,
+ step,
+ tagName,
+ evalMissingEntry,
+ }: IProcessXML
+) {
+ const doc = await FileIO.loadXML(path);
+
+ const containerElement =
+ (containerQuery && doc.querySelector(containerQuery)) || doc.documentElement;
+
+ migrationMap.forEach((migItem, originalToken) => {
+ migItem.step[step] = 'ignore';
+
+ const queryTiems = containerElement.querySelectorAll(
+ `${tagName}[${attr}="${originalToken}"]`
+ );
+
+ if (evalMissingEntry) {
+ const addinOptions = evalMissingEntry(originalToken, migItem);
+
+ if (queryTiems.length == 0 && containerElement && addinOptions) {
+ DOM.addEntry(containerElement, addinOptions);
+ migItem.step[step] = 'add';
+ return;
+ }
+ }
+
+ if (evalExistingEntry)
+ queryTiems.forEach((qEl) => {
+ const attrName = qEl.getAttribute(attr);
+ const migItem = migrationMap.get(attrName || '');
+
+ if (!attrName || !migItem) return;
+
+ const updateOptions = evalExistingEntry(attrName, migItem, qEl);
+
+ if (!updateOptions) return;
+
+ const [processType, processOptions] = updateOptions;
+
+ switch (processType) {
+ case 'update':
+ if (DOM.updateElement(qEl, processOptions)) migItem.step[step] = 'update';
+ break;
+
+ case 'duplicate':
+ if (DOM.duplicateEntryWithChange(qEl, processOptions))
+ migItem.step[step] = 'duplicate';
+ break;
+ }
+ });
+ });
+
+ await FileIO.saveFile(doc.documentElement.outerHTML, path);
+}
diff --git a/packages/SystemUI/scripts/token_alignment/helpers/rootPath.ts b/packages/SystemUI/scripts/token_alignment/helpers/rootPath.ts
new file mode 100644
index 0000000..2c6f632
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/helpers/rootPath.ts
@@ -0,0 +1,21 @@
+// Copyright 2022 Google LLC
+
+// 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.import { exec } from 'child_process';
+
+if (!process?.env?.ANDROID_BUILD_TOP) {
+ console.log(
+ "Error: Couldn't find 'ANDROID_BUILD_TOP' environment variable. Make sure to run 'lunch' in this terminal"
+ );
+}
+
+export const repoPath = process?.env?.ANDROID_BUILD_TOP;
diff --git a/packages/SystemUI/scripts/token_alignment/helpers/textFuncs.ts b/packages/SystemUI/scripts/token_alignment/helpers/textFuncs.ts
new file mode 100644
index 0000000..6679c5a
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/helpers/textFuncs.ts
@@ -0,0 +1,27 @@
+// Copyright 2022 Google LLC
+
+// 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.import { exec } from 'child_process';
+
+export function groupReplace(src: string, replaceMap: Map<string, string>, pattern: string) {
+ const fullPattern = pattern.replace('#group#', [...replaceMap.keys()].join('|'));
+
+ const regEx = new RegExp(fullPattern, 'g');
+
+ ''.replace;
+
+ return src.replace(regEx, (...args) => {
+ //match, ...matches, offset, string, groups
+ const [match, key] = args as string[];
+ return match.replace(key, replaceMap.get(key) || '');
+ });
+}
diff --git a/packages/SystemUI/scripts/token_alignment/index.ts b/packages/SystemUI/scripts/token_alignment/index.ts
new file mode 100644
index 0000000..1b15e48
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/index.ts
@@ -0,0 +1,240 @@
+// Copyright 2022 Google LLC
+
+// 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.import { exec } from 'child_process';
+
+import DOM from './helpers/DOMFuncs';
+import { FileIO } from './helpers/FileIO';
+import { loadMIgrationList } from './helpers/migrationList';
+import { processQueriedEntries, TEvalExistingEntry } from './helpers/processXML';
+import { repoPath } from './helpers/rootPath';
+import { groupReplace } from './helpers/textFuncs';
+
+async function init() {
+ const migrationMap = await loadMIgrationList();
+ const basePath = `${repoPath}/../tm-qpr-dev/frameworks/base/core/res/res/values/`;
+
+ await processQueriedEntries(migrationMap, {
+ containerQuery: 'declare-styleable[name="Theme"]',
+ hidable: true,
+ path: `${basePath}attrs.xml`,
+ step: 0,
+ tagName: 'attr',
+ evalExistingEntry: (_attrValue, migItem, qItem) => {
+ const { hidden, textContent: currentComment } = DOM.getElementComment(qItem);
+
+ if (hidden) migItem.isHidden = hidden;
+
+ const { newComment } = migItem;
+ return [
+ hidden ? 'update' : 'duplicate',
+ {
+ attrs: { name: migItem.replaceToken },
+ ...(newComment
+ ? { comment: `${newComment} @hide ` }
+ : currentComment
+ ? { comment: hidden ? currentComment : `${currentComment} @hide ` }
+ : {}),
+ },
+ ];
+ },
+ evalMissingEntry: (_originalToken, { replaceToken, newComment }) => {
+ return {
+ tagName: 'attr',
+ attrs: {
+ name: replaceToken,
+ format: 'color',
+ },
+ comment: `${newComment} @hide `,
+ };
+ },
+ });
+
+ // only update all existing entries
+ await processQueriedEntries(migrationMap, {
+ tagName: 'item',
+ path: `${basePath}themes_device_defaults.xml`,
+ containerQuery: 'resources',
+ step: 2,
+ evalExistingEntry: (_attrValue, { isHidden, replaceToken, step }, _qItem) => {
+ if (step[0] != 'ignore')
+ return [
+ isHidden ? 'update' : 'duplicate',
+ {
+ attrs: { name: replaceToken },
+ },
+ ];
+ },
+ });
+
+ // add missing entries on specific container
+ await processQueriedEntries(migrationMap, {
+ tagName: 'item',
+ path: `${basePath}themes_device_defaults.xml`,
+ containerQuery: 'resources style[parent="Theme.Material"]',
+ step: 3,
+ evalMissingEntry: (originalToken, { newDefaultValue, replaceToken }) => {
+ return {
+ tagName: 'item',
+ content: newDefaultValue,
+ attrs: {
+ name: replaceToken,
+ },
+ };
+ },
+ });
+
+ const evalExistingEntry: TEvalExistingEntry = (_attrValue, { replaceToken, step }, _qItem) => {
+ if (step[0] == 'update')
+ return [
+ 'update',
+ {
+ attrs: { name: replaceToken },
+ },
+ ];
+ };
+
+ await processQueriedEntries(migrationMap, {
+ tagName: 'item',
+ containerQuery: 'resources',
+ path: `${basePath}../values-night/themes_device_defaults.xml`,
+ step: 4,
+ evalExistingEntry,
+ });
+
+ await processQueriedEntries(migrationMap, {
+ tagName: 'java-symbol',
+ path: `${basePath}symbols.xml`,
+ containerQuery: 'resources',
+ step: 5,
+ evalExistingEntry,
+ });
+
+ // update attributes on tracked XML files
+ {
+ const searchAttrs = [
+ 'android:color',
+ 'android:indeterminateTint',
+ 'app:tint',
+ 'app:backgroundTint',
+ 'android:background',
+ 'android:tint',
+ 'android:drawableTint',
+ 'android:textColor',
+ 'android:fillColor',
+ 'android:startColor',
+ 'android:endColor',
+ 'name',
+ 'ns1:color',
+ ];
+
+ const filtered = new Map(
+ [...migrationMap]
+ .filter(([_originalToken, { step }]) => step[0] == 'update')
+ .map(([originalToken, { replaceToken }]) => [originalToken, replaceToken])
+ );
+
+ const query =
+ searchAttrs.map((str) => `*[${str}]`).join(',') +
+ [...filtered.keys()].map((originalToken) => `item[name*="${originalToken}"]`).join(',');
+
+ const trackedFiles = await FileIO.loadFileList(
+ `${__dirname}/resources/whitelist/xmls1.json`
+ );
+
+ const promises = trackedFiles.map(async (locaFilePath) => {
+ const filePath = `${repoPath}/${locaFilePath}`;
+
+ const doc = await FileIO.loadXML(filePath);
+ const docUpdated = DOM.replaceStringInAttributeValueOnQueried(
+ doc.documentElement,
+ query,
+ searchAttrs,
+ filtered
+ );
+ if (docUpdated) {
+ await FileIO.saveFile(DOM.XMLDocToString(doc), filePath);
+ } else {
+ console.warn(`Failed to update tracked file: '${locaFilePath}'`);
+ }
+ });
+ await Promise.all(promises);
+ }
+
+ // updates tag content on tracked files
+ {
+ const searchPrefixes = ['?android:attr/', '?androidprv:attr/'];
+ const filtered = searchPrefixes
+ .reduce<Array<[string, string]>>((acc, prefix) => {
+ return [
+ ...acc,
+ ...[...migrationMap.entries()]
+ .filter(([_originalToken, { step }]) => step[0] == 'update')
+ .map(
+ ([originalToken, { replaceToken }]) =>
+ [`${prefix}${originalToken}`, `${prefix}${replaceToken}`] as [
+ string,
+ string
+ ]
+ ),
+ ];
+ }, [])
+ .sort((a, b) => b[0].length - a[0].length);
+
+ const trackedFiles = await FileIO.loadFileList(
+ `${__dirname}/resources/whitelist/xmls2.json`
+ );
+
+ const promises = trackedFiles.map(async (locaFilePath) => {
+ const filePath = `${repoPath}/${locaFilePath}`;
+ const doc = await FileIO.loadXML(filePath);
+ const docUpdated = DOM.replaceContentTextOnQueried(
+ doc.documentElement,
+ 'item, color',
+ filtered
+ );
+ if (docUpdated) {
+ await FileIO.saveFile(DOM.XMLDocToString(doc), filePath);
+ } else {
+ console.warn(`Failed to update tracked file: '${locaFilePath}'`);
+ }
+ });
+ await Promise.all(promises);
+ }
+
+ // replace imports on Java / Kotlin
+ {
+ const replaceMap = new Map(
+ [...migrationMap.entries()]
+ .filter(([_originalToken, { step }]) => step[0] == 'update')
+ .map(
+ ([originalToken, { replaceToken }]) =>
+ [originalToken, replaceToken] as [string, string]
+ )
+ .sort((a, b) => b[0].length - a[0].length)
+ );
+
+ const trackedFiles = await FileIO.loadFileList(
+ `${__dirname}/resources/whitelist/java.json`
+ );
+
+ const promises = trackedFiles.map(async (locaFilePath) => {
+ const filePath = `${repoPath}/${locaFilePath}`;
+ const fileContent = await FileIO.loadFileAsText(filePath);
+ const str = groupReplace(fileContent, replaceMap, 'R.attr.(#group#)(?![a-zA-Z])');
+ await FileIO.saveFile(str, filePath);
+ });
+ await Promise.all(promises);
+ }
+}
+
+init();
diff --git a/packages/SystemUI/scripts/token_alignment/package-lock.json b/packages/SystemUI/scripts/token_alignment/package-lock.json
new file mode 100644
index 0000000..da9edb3
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/package-lock.json
@@ -0,0 +1,3356 @@
+{
+ "name": "token_alignment",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "csv-parse": "^5.3.3",
+ "high5": "^1.0.0",
+ "jsdom": "^20.0.3"
+ },
+ "devDependencies": {
+ "@types/jsdom": "^20.0.1",
+ "@types/node": "^18.11.18",
+ "@typescript-eslint/eslint-plugin": "^5.48.0",
+ "eslint-config-prettier": "^8.6.0",
+ "eslint-plugin-import": "^2.26.0",
+ "eslint-plugin-prettier": "^4.2.1",
+ "eslint-plugin-simple-import-sort": "^8.0.0",
+ "ts-node": "^10.9.1",
+ "typescript": "^4.9.4"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
+ "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.4.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.8",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
+ "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.1",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.4.14",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@tootallnate/once": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
+ "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
+ "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
+ "dev": true
+ },
+ "node_modules/@types/jsdom": {
+ "version": "20.0.1",
+ "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz",
+ "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/tough-cookie": "*",
+ "parse5": "^7.0.0"
+ }
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.11",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+ "dev": true
+ },
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "18.11.18",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
+ "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==",
+ "dev": true
+ },
+ "node_modules/@types/semver": {
+ "version": "7.3.13",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
+ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
+ "dev": true
+ },
+ "node_modules/@types/tough-cookie": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz",
+ "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==",
+ "dev": true
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz",
+ "integrity": "sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.48.0",
+ "@typescript-eslint/type-utils": "5.48.0",
+ "@typescript-eslint/utils": "5.48.0",
+ "debug": "^4.3.4",
+ "ignore": "^5.2.0",
+ "natural-compare-lite": "^1.4.0",
+ "regexpp": "^3.2.0",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^5.0.0",
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.0.tgz",
+ "integrity": "sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "5.48.0",
+ "@typescript-eslint/types": "5.48.0",
+ "@typescript-eslint/typescript-estree": "5.48.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz",
+ "integrity": "sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.48.0",
+ "@typescript-eslint/visitor-keys": "5.48.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz",
+ "integrity": "sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "5.48.0",
+ "@typescript-eslint/utils": "5.48.0",
+ "debug": "^4.3.4",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.0.tgz",
+ "integrity": "sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz",
+ "integrity": "sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.48.0",
+ "@typescript-eslint/visitor-keys": "5.48.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.3.7",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.0.tgz",
+ "integrity": "sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "5.48.0",
+ "@typescript-eslint/types": "5.48.0",
+ "@typescript-eslint/typescript-estree": "5.48.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0",
+ "semver": "^7.3.7"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/utils/node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "5.48.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz",
+ "integrity": "sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "5.48.0",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/abab": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
+ "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
+ },
+ "node_modules/acorn": {
+ "version": "8.8.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
+ "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-globals": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz",
+ "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==",
+ "dependencies": {
+ "acorn": "^8.1.0",
+ "acorn-walk": "^8.0.2"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peer": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
+ "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4",
+ "get-intrinsic": "^1.1.3",
+ "is-string": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz",
+ "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
+ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cssom": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
+ "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="
+ },
+ "node_modules/cssstyle": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
+ "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+ "dependencies": {
+ "cssom": "~0.3.6"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cssstyle/node_modules/cssom": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
+ },
+ "node_modules/csv-parse": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.3.3.tgz",
+ "integrity": "sha512-kEWkAPleNEdhFNkHQpFHu9RYPogsFj3dx6bCxL847fsiLgidzWg0z/O0B1kVWMJUc5ky64zGp18LX2T3DQrOfw=="
+ },
+ "node_modules/data-urls": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
+ "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
+ "dependencies": {
+ "abab": "^2.0.6",
+ "whatwg-mimetype": "^3.0.0",
+ "whatwg-url": "^11.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decimal.js": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+ "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
+ },
+ "node_modules/define-properties": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
+ "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
+ "dev": true,
+ "dependencies": {
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/domexception": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
+ "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
+ "dependencies": {
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+ "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.0.tgz",
+ "integrity": "sha512-GUGtW7eXQay0c+PRq0sGIKSdaBorfVqsCMhGHo4elP7YVqZu9nCZS4UkK4gv71gOWNMra/PaSKD3ao1oWExO0g==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "es-set-tostringtag": "^2.0.0",
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "function.prototype.name": "^1.1.5",
+ "get-intrinsic": "^1.1.3",
+ "get-symbol-description": "^1.0.0",
+ "globalthis": "^1.0.3",
+ "gopd": "^1.0.1",
+ "has": "^1.0.3",
+ "has-property-descriptors": "^1.0.0",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "internal-slot": "^1.0.4",
+ "is-array-buffer": "^3.0.0",
+ "is-callable": "^1.2.7",
+ "is-negative-zero": "^2.0.2",
+ "is-regex": "^1.1.4",
+ "is-shared-array-buffer": "^1.0.2",
+ "is-string": "^1.0.7",
+ "is-typed-array": "^1.1.10",
+ "is-weakref": "^1.0.2",
+ "object-inspect": "^1.12.2",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.4",
+ "regexp.prototype.flags": "^1.4.3",
+ "safe-regex-test": "^1.0.0",
+ "string.prototype.trimend": "^1.0.6",
+ "string.prototype.trimstart": "^1.0.6",
+ "typed-array-length": "^1.0.4",
+ "unbox-primitive": "^1.0.2",
+ "which-typed-array": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
+ "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3",
+ "has": "^1.0.3",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
+ "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/escodegen": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
+ "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.31.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz",
+ "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "@eslint/eslintrc": "^1.4.1",
+ "@humanwhocodes/config-array": "^0.11.8",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.1.1",
+ "eslint-utils": "^3.0.0",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.4.0",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "grapheme-splitter": "^1.0.4",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-sdsl": "^4.1.4",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "regexpp": "^3.2.0",
+ "strip-ansi": "^6.0.1",
+ "strip-json-comments": "^3.1.0",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "8.6.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz",
+ "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
+ "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^3.2.7",
+ "resolve": "^1.20.0"
+ }
+ },
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-module-utils": {
+ "version": "2.7.4",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz",
+ "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^3.2.7"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import": {
+ "version": "2.26.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
+ "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.4",
+ "array.prototype.flat": "^1.2.5",
+ "debug": "^2.6.9",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.6",
+ "eslint-module-utils": "^2.7.3",
+ "has": "^1.0.3",
+ "is-core-module": "^2.8.1",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.values": "^1.1.5",
+ "resolve": "^1.22.0",
+ "tsconfig-paths": "^3.14.1"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
+ },
+ "node_modules/eslint-plugin-prettier": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+ "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+ "dev": true,
+ "dependencies": {
+ "prettier-linter-helpers": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.28.0",
+ "prettier": ">=2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-simple-import-sort": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz",
+ "integrity": "sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==",
+ "dev": true,
+ "peerDependencies": {
+ "eslint": ">=5.0.0"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+ "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+ "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=5"
+ }
+ },
+ "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/eslint/node_modules/optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/eslint/node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/eslint/node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.4.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz",
+ "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "acorn": "^8.8.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+ "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
+ "node_modules/fast-glob": {
+ "version": "3.2.12",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+ "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
+ },
+ "node_modules/fastq": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+ "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+ "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
+ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.3"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/function.prototype.name": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
+ "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.19.0",
+ "functions-have-names": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
+ "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-symbol-description": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
+ "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.19.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
+ "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
+ "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-bigints": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+ "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
+ "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+ "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
+ "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/high5": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/high5/-/high5-1.0.0.tgz",
+ "integrity": "sha512-xucW/5M1hd+p6bj530wtRSKwqUQrgiIgOWepi4Di9abkonZaxhTDf0zrqqraxfZSXBcFSuc1/WVGBIlqSe1Hdw==",
+ "dependencies": {
+ "entities": "1.0"
+ }
+ },
+ "node_modules/high5/node_modules/entities": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
+ "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ=="
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
+ "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+ "dependencies": {
+ "whatwg-encoding": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
+ "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
+ "dependencies": {
+ "@tootallnate/once": "2",
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.2.4",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+ "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/internal-slot": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz",
+ "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3",
+ "has": "^1.0.3",
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz",
+ "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.1.3",
+ "is-typed-array": "^1.1.10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+ "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "dev": true,
+ "dependencies": {
+ "has-bigints": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+ "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
+ "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+ "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
+ "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+ "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
+ },
+ "node_modules/is-regex": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+ "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
+ "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+ "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+ "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz",
+ "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.5",
+ "call-bind": "^1.0.2",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+ "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/js-sdsl": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
+ "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
+ "dev": true,
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/js-sdsl"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsdom": {
+ "version": "20.0.3",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
+ "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==",
+ "dependencies": {
+ "abab": "^2.0.6",
+ "acorn": "^8.8.1",
+ "acorn-globals": "^7.0.0",
+ "cssom": "^0.5.0",
+ "cssstyle": "^2.3.0",
+ "data-urls": "^3.0.2",
+ "decimal.js": "^10.4.2",
+ "domexception": "^4.0.0",
+ "escodegen": "^2.0.0",
+ "form-data": "^4.0.0",
+ "html-encoding-sniffer": "^3.0.0",
+ "http-proxy-agent": "^5.0.0",
+ "https-proxy-agent": "^5.0.1",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.2",
+ "parse5": "^7.1.1",
+ "saxes": "^6.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^4.1.2",
+ "w3c-xmlserializer": "^4.0.0",
+ "webidl-conversions": "^7.0.0",
+ "whatwg-encoding": "^2.0.0",
+ "whatwg-mimetype": "^3.0.0",
+ "whatwg-url": "^11.0.0",
+ "ws": "^8.11.0",
+ "xml-name-validator": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "canvas": "^2.5.0"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
+ "dependencies": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+ "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.2",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
+ "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
+ "dev": true
+ },
+ "node_modules/nwsapi": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz",
+ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw=="
+ },
+ "node_modules/object-inspect": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
+ "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "has-symbols": "^1.0.3",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
+ "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dependencies": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+ "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+ "dependencies": {
+ "entities": "^4.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.2.tgz",
+ "integrity": "sha512-BtRV9BcncDyI2tsuS19zzhzoxD8Dh8LiCx7j7tHzrkz8GFXAexeWFdi22mjE1d16dftH2qNaytVxqiRTGlMfpw==",
+ "dev": true,
+ "peer": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/psl": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
+ "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3",
+ "functions-have-names": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
+ },
+ "node_modules/resolve": {
+ "version": "1.22.1",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+ "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.9.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
+ "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.1.3",
+ "is-regex": "^1.1.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.3.8",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+ "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
+ "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
+ "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.4",
+ "es-abstract": "^1.20.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
+ "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.2.0",
+ "url-parse": "^1.5.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
+ "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
+ "dependencies": {
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/ts-node": {
+ "version": "10.9.1",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
+ "dev": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
+ "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.1",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "node_modules/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
+ "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "for-each": "^0.3.3",
+ "is-typed-array": "^1.1.9"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.9.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
+ "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+ "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.0.3",
+ "which-boxed-primitive": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "dev": true
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
+ "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
+ "dependencies": {
+ "xml-name-validator": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
+ "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
+ "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
+ "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
+ "dependencies": {
+ "tr46": "^3.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "peer": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+ "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+ "dev": true,
+ "dependencies": {
+ "is-bigint": "^1.0.1",
+ "is-boolean-object": "^1.1.0",
+ "is-number-object": "^1.0.4",
+ "is-string": "^1.0.5",
+ "is-symbol": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz",
+ "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.5",
+ "call-bind": "^1.0.2",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.0",
+ "is-typed-array": "^1.1.10"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "peer": true
+ },
+ "node_modules/ws": {
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
+ "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
+ "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/scripts/token_alignment/package.json b/packages/SystemUI/scripts/token_alignment/package.json
new file mode 100644
index 0000000..2e63668
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/package.json
@@ -0,0 +1,22 @@
+{
+ "dependencies": {
+ "csv-parse": "^5.3.3",
+ "high5": "^1.0.0",
+ "jsdom": "^20.0.3"
+ },
+ "devDependencies": {
+ "@types/jsdom": "^20.0.1",
+ "@types/node": "^18.11.18",
+ "@typescript-eslint/eslint-plugin": "^5.48.0",
+ "eslint-config-prettier": "^8.6.0",
+ "eslint-plugin-import": "^2.26.0",
+ "eslint-plugin-prettier": "^4.2.1",
+ "eslint-plugin-simple-import-sort": "^8.0.0",
+ "ts-node": "^10.9.1",
+ "typescript": "^4.9.4"
+ },
+ "scripts": {
+ "main": "ts-node ./index.ts",
+ "resetRepo": "repo forall -j100 -c 'git restore .'"
+ }
+}
diff --git a/packages/SystemUI/scripts/token_alignment/resources/migrationList.csv b/packages/SystemUI/scripts/token_alignment/resources/migrationList.csv
new file mode 100644
index 0000000..4111bb3
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/resources/migrationList.csv
@@ -0,0 +1,16 @@
+android material newDefaultValue newComment migrationToken
+colorAccentPrimaryVariant colorPrimaryContainer MigTok02
+colorAccentSecondaryVariant colorSecondaryContainer MigTok04
+colorAccentTertiary colorTertiary MigTok05
+colorAccentTertiaryVariant colorTertiaryContainer MigTok06
+colorBackground colorSurfaceContainer MigTok07
+colorSurface colorSurfaceContainer MigTok08
+colorSurfaceHeader colorSurfaceContainerHighest MigTok09
+colorSurfaceHighlight colorSurfaceBright MigTok10
+colorSurfaceVariant colorSurfaceContainerHigh MigTok11
+textColorOnAccent colorOnPrimary MigTok12
+textColorPrimary colorOnSurface MigTok13
+textColorPrimaryInverse colorOnShadeInactive MigTok14
+textColorSecondary colorOnSurfaceVariant MigTok15
+textColorSecondaryInverse colorOnShadeInactiveVariant MigTok16
+textColorTertiary colorOutline MigTok17
\ No newline at end of file
diff --git a/packages/SystemUI/scripts/token_alignment/resources/whitelist/java.json b/packages/SystemUI/scripts/token_alignment/resources/whitelist/java.json
new file mode 100644
index 0000000..7f55b2d
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/resources/whitelist/java.json
@@ -0,0 +1,30 @@
+[
+ "frameworks/base/core/java/android/app/Notification.java",
+ "packages/apps/Settings/src/com/android/settings/dashboard/profileselector/UserAdapter.java",
+ "packages/apps/Settings/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java",
+ "frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflow.kt",
+ "frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/ManageEducationView.kt",
+ "packages/apps/WallpaperPicker2/src/com/android/wallpaper/picker/PreviewFragment.java",
+ "packages/apps/WallpaperPicker2/src/com/android/wallpaper/picker/CategorySelectorFragment.java",
+ "packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt",
+ "frameworks/base/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleFlyoutView.java",
+ "vendor/unbundled_google/packages/NexusLauncher/src/com/google/android/apps/nexuslauncher/customize/WallpaperCarouselView.java",
+ "vendor/unbundled_google/packages/NexusLauncher/src/com/google/android/apps/nexuslauncher/quickstep/TaskOverlayFactoryImpl.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/people/ui/view/PeopleViewBinder.kt",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserViewBinder.kt",
+ "frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java",
+ "frameworks/base/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java",
+ "frameworks/base/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java"
+]
\ No newline at end of file
diff --git a/packages/SystemUI/scripts/token_alignment/resources/whitelist/xmls1.json b/packages/SystemUI/scripts/token_alignment/resources/whitelist/xmls1.json
new file mode 100644
index 0000000..1e59773
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/resources/whitelist/xmls1.json
@@ -0,0 +1,184 @@
+[
+ "frameworks/base/core/res/res/color/resolver_profile_tab_selected_bg.xml",
+ "frameworks/base/core/res/res/color-night/resolver_profile_tab_selected_bg.xml",
+ "frameworks/base/core/res/res/drawable/autofill_bottomsheet_background.xml",
+ "frameworks/base/core/res/res/drawable/btn_outlined.xml",
+ "frameworks/base/core/res/res/drawable/btn_tonal.xml",
+ "frameworks/base/core/res/res/drawable/chooser_action_button_bg.xml",
+ "frameworks/base/core/res/res/drawable/chooser_row_layer_list.xml",
+ "frameworks/base/core/res/res/drawable/resolver_outlined_button_bg.xml",
+ "frameworks/base/core/res/res/drawable/resolver_profile_tab_bg.xml",
+ "frameworks/base/core/res/res/drawable/toast_frame.xml",
+ "frameworks/base/core/res/res/drawable/work_widget_mask_view_background.xml",
+ "frameworks/base/core/res/res/layout/app_language_picker_current_locale_item.xml",
+ "frameworks/base/core/res/res/layout/app_language_picker_system_current.xml",
+ "frameworks/base/core/res/res/layout/autofill_save.xml",
+ "frameworks/base/core/res/res/layout/chooser_grid.xml",
+ "frameworks/base/core/res/res/layout/user_switching_dialog.xml",
+ "frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_left_bk.xml",
+ "frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/half_rounded_right_bk.xml",
+ "frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/rounded_bk.xml",
+ "frameworks/base/packages/SettingsLib/ActionButtonsPreference/res/drawable/square_bk.xml",
+ "packages/modules/IntentResolver/java/res/drawable/chooser_action_button_bg.xml",
+ "packages/modules/IntentResolver/java/res/drawable/chooser_row_layer_list.xml",
+ "packages/modules/IntentResolver/java/res/drawable/resolver_outlined_button_bg.xml",
+ "packages/modules/IntentResolver/java/res/drawable/resolver_profile_tab_bg.xml",
+ "packages/modules/IntentResolver/java/res/layout/chooser_grid.xml",
+ "frameworks/base/libs/WindowManager/Shell/res/color/one_handed_tutorial_background_color.xml",
+ "frameworks/base/libs/WindowManager/Shell/res/drawable/bubble_manage_menu_bg.xml",
+ "frameworks/base/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg.xml",
+ "frameworks/base/libs/WindowManager/Shell/res/drawable/bubble_stack_user_education_bg_rtl.xml",
+ "vendor/unbundled_google/packages/SystemUIGoogle/bcsmartspace/res/drawable/bg_smartspace_combination_sub_card.xml",
+ "vendor/unbundled_google/packages/SystemUIGoogle/bcsmartspace/res/layout/smartspace_combination_sub_card.xml",
+ "packages/apps/Launcher3/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml",
+ "packages/apps/Launcher3/res/drawable/rounded_action_button.xml",
+ "packages/apps/Launcher3/res/drawable/work_card.xml",
+ "packages/apps/Nfc/res/color/nfc_icon.xml",
+ "packages/apps/Nfc/res/color-night/nfc_icon.xml",
+ "packages/apps/Launcher3/quickstep/res/drawable/bg_overview_clear_all_button.xml",
+ "packages/apps/Launcher3/quickstep/res/drawable/bg_sandbox_feedback.xml",
+ "packages/apps/Launcher3/quickstep/res/drawable/bg_wellbeing_toast.xml",
+ "packages/apps/Launcher3/quickstep/res/drawable/button_taskbar_edu_bordered.xml",
+ "packages/apps/Launcher3/quickstep/res/drawable/button_taskbar_edu_colored.xml",
+ "packages/apps/Launcher3/quickstep/res/drawable/split_instructions_background.xml",
+ "packages/apps/Launcher3/quickstep/res/drawable/task_menu_item_bg.xml",
+ "packages/apps/Launcher3/quickstep/res/layout/digital_wellbeing_toast.xml",
+ "packages/apps/Launcher3/quickstep/res/layout/split_instructions_view.xml",
+ "packages/apps/Launcher3/quickstep/res/layout/taskbar_edu.xml",
+ "frameworks/base/packages/SettingsLib/res/drawable/broadcast_dialog_btn_bg.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color/share_target_text.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-v31/all_apps_tab_background_selected.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-v31/all_apps_tabs_background.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-v31/arrow_tip_view_bg.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-v31/button_bg.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-v31/shortcut_halo.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-v31/surface.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-night-v31/all_apps_tab_background_selected.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/color-night-v31/surface.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/bg_pin_keyboard_snackbar_accept_button.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/bg_search_edu_preferences_button.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/circle_accentprimary_32dp.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/ic_search.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/ic_suggest_icon_background.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/share_target_background.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/sticky_snackbar_accept_btn_background.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/sticky_snackbar_background.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/sticky_snackbar_dismiss_btn_background.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/drawable/tall_card_btn_background.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/layout/section_header.xml",
+ "packages/apps/Settings/res/color/dream_card_color_state_list.xml",
+ "packages/apps/Settings/res/color/dream_card_icon_color_state_list.xml",
+ "packages/apps/Settings/res/color/dream_card_text_color_state_list.xml",
+ "packages/apps/Settings/res/drawable/accessibility_text_reading_preview.xml",
+ "packages/apps/Settings/res/drawable/broadcast_button_outline.xml",
+ "packages/apps/Settings/res/drawable/button_border_selected.xml",
+ "packages/apps/Settings/res/drawable/dream_preview_rounded_bg.xml",
+ "packages/apps/Settings/res/drawable/rounded_bg.xml",
+ "packages/apps/Settings/res/drawable/sim_confirm_dialog_btn_outline.xml",
+ "packages/apps/Settings/res/drawable/user_select_background.xml",
+ "packages/apps/Settings/res/drawable/volume_dialog_button_background_outline.xml",
+ "packages/apps/Settings/res/drawable/volume_dialog_button_background_solid.xml",
+ "packages/apps/Settings/res/layout/dream_preview_button.xml",
+ "packages/apps/Settings/res/layout/qrcode_scanner_fragment.xml",
+ "frameworks/base/packages/SystemUI/res/values-television/styles.xml",
+ "frameworks/base/packages/SystemUI/res/color/media_player_album_bg.xml",
+ "frameworks/base/packages/SystemUI/res/color/media_player_outline_button_bg.xml",
+ "frameworks/base/packages/SystemUI/res/color/media_player_solid_button_bg.xml",
+ "frameworks/base/packages/SystemUI/res-keyguard/color/numpad_key_color_secondary.xml",
+ "frameworks/base/packages/SystemUI/res/color/settingslib_state_on.xml",
+ "frameworks/base/packages/SystemUI/res/color/settingslib_track_off.xml",
+ "frameworks/base/packages/SystemUI/res/color/settingslib_track_on.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/accessibility_floating_tooltip_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/action_chip_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/action_chip_container_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/availability_dot_10dp.xml",
+ "frameworks/base/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml",
+ "frameworks/base/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_item_selected_bg.xml",
+ "frameworks/base/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_popup_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/broadcast_dialog_btn_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/fgs_dot.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/fingerprint_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/ic_avatar_with_badge.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml",
+ "frameworks/base/packages/SystemUI/res-keyguard/drawable/kg_bouncer_secondary_button.xml",
+ "frameworks/base/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/logout_button_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/media_ttt_chip_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/media_ttt_chip_background_receiver.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/media_ttt_undo_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/notif_footer_btn_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/notification_guts_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/notification_material_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/overlay_badge_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/overlay_border.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/overlay_button_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/overlay_cancel.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/people_space_messages_count_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/people_tile_status_scrim.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/people_tile_suppressed_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/qs_dialog_btn_filled.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/qs_dialog_btn_outline.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/qs_media_outline_button.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/qs_media_solid_button.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/rounded_bg_full.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/rounded_bg_full_large_radius.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/screenrecord_button_background_solid.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/screenrecord_spinner_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/screenshot_edit_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/user_switcher_fullscreen_button_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/vector_drawable_progress_indeterminate_horizontal_trimmed.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/volume_background_bottom.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/volume_background_top.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/volume_background_top_rounded.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/volume_row_rounded_background.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/volume_row_seekbar.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/wallet_action_button_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/wallet_app_button_bg.xml",
+ "frameworks/base/packages/SystemUI/res/drawable/wallet_empty_state_bg.xml",
+ "frameworks/base/packages/SystemUI/res/layout/alert_dialog_title_systemui.xml",
+ "frameworks/base/packages/SystemUI/res/layout/chipbar.xml",
+ "frameworks/base/packages/SystemUI/res/layout/chipbar.xml",
+ "frameworks/base/packages/SystemUI/res/layout/clipboard_overlay.xml",
+ "frameworks/base/packages/SystemUI/res/layout/clipboard_overlay.xml",
+ "frameworks/base/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml",
+ "frameworks/base/packages/SystemUI/res/layout/clipboard_overlay_legacy.xml",
+ "frameworks/base/packages/SystemUI/res/layout/internet_connectivity_dialog.xml",
+ "frameworks/base/packages/SystemUI/res/layout/notification_snooze.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_space_activity_no_conversations.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_space_activity_with_conversations.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_space_activity_with_conversations.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_space_tile_view.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_large_with_content.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_medium_with_content.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_large.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_large.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_large.xml",
+ "frameworks/base/packages/SystemUI/res/layout/chipbar.xml",
+ "frameworks/base/packages/SystemUI/res/layout/notification_snooze.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_medium.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_medium.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_medium.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_medium.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_punctuation_background_medium.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_small.xml",
+ "frameworks/base/packages/SystemUI/res/layout/people_tile_small_horizontal.xml",
+ "frameworks/base/packages/SystemUI/res/layout/screen_share_dialog.xml",
+ "frameworks/base/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml",
+ "frameworks/base/packages/SystemUI/res/layout/user_switcher_fullscreen.xml",
+ "frameworks/base/packages/SystemUI/res/layout/user_switcher_fullscreen.xml",
+ "frameworks/base/packages/SystemUI/res/layout/wallet_empty_state.xml",
+ "frameworks/base/packages/SystemUI/res/layout/wallet_fullscreen.xml",
+ "frameworks/base/packages/SystemUI/res/layout/wallet_fullscreen.xml",
+ "frameworks/base/packages/SystemUI/res/layout/chipbar.xml",
+ "frameworks/base/packages/SystemUI/res/layout/notification_snooze.xml",
+ "vendor/unbundled_google/packages/SystemUIGoogle/res/drawable/columbus_chip_background_raw.xml",
+ "vendor/unbundled_google/packages/SystemUIGoogle/res/drawable/columbus_chip_background_raw.xml",
+ "vendor/unbundled_google/packages/SystemUIGoogle/res/drawable/columbus_dialog_background.xml",
+ "vendor/unbundled_google/packages/SystemUIGoogle/res/layout/columbus_target_request_dialog.xml",
+ "vendor/unbundled_google/packages/SettingsGoogle/res/color/dream_card_suw_color_state_list.xml",
+ "vendor/unbundled_google/packages/SettingsGoogle/res/drawable/dream_item_suw_rounded_bg.xml"
+]
\ No newline at end of file
diff --git a/packages/SystemUI/scripts/token_alignment/resources/whitelist/xmls2.json b/packages/SystemUI/scripts/token_alignment/resources/whitelist/xmls2.json
new file mode 100644
index 0000000..20a7c76
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/resources/whitelist/xmls2.json
@@ -0,0 +1,13 @@
+[
+ "vendor/google/nexus_overlay/PixelDocumentsUIGoogleOverlay/res/values-v31/themes.xml",
+ "vendor/google/nexus_overlay/PixelDocumentsUIGoogleOverlay/res/values-night-v31/themes.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/values/colors.xml",
+ "vendor/unbundled_google/packages/NexusLauncher/res/values/styles.xml",
+ "packages/apps/Settings/res/values-night/colors.xml",
+ "packages/apps/Settings/res/values/colors.xml",
+ "packages/apps/Settings/res/values/styles.xml",
+ "frameworks/base/packages/SystemUI/res-keyguard/values/styles.xml",
+ "frameworks/base/packages/SystemUI/res/values/styles.xml",
+ "vendor/unbundled_google/packages/SettingsGoogle/res/values/styles.xml",
+ "vendor/unbundled_google/packages/SettingsGoogle/res/values/styles.xml"
+]
\ No newline at end of file
diff --git a/packages/SystemUI/scripts/token_alignment/tsconfig.json b/packages/SystemUI/scripts/token_alignment/tsconfig.json
new file mode 100644
index 0000000..20c7321
--- /dev/null
+++ b/packages/SystemUI/scripts/token_alignment/tsconfig.json
@@ -0,0 +1,103 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig to read more about this file */
+
+ /* Projects */
+ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
+ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
+
+ /* Language and Environment */
+ "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
+ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+ // "jsxFragmentFactory": "", /* Speciffy the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
+
+ /* Modules */
+ "module": "commonjs", /* Specify what module code is generated. */
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ "typeRoots": ["../node_modules/@types"], /* Specify multiple folders that act like './node_modules/@types'. */
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
+ "resolveJsonModule": true, /* Enable importing .json files. */
+ // "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
+
+ /* JavaScript Support */
+ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
+ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+
+ /* Emit */
+ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
+ "sourceMap": true, /* Create source map files for emitted JavaScript files. */
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+ // "outDir": "./", /* Specify an output folder for all emitted files. */
+ // "removeComments": true, /* Disable emitting comments. */
+ // "noEmit": true, /* Disable emitting files from a compilation. */
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
+ // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
+ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
+ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
+ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
+
+ /* Interop Constraints */
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+
+ /* Type Checking */
+ "strict": true, /* Enable all strict type-checking options. */
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
+ // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
+ // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
+ // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
+ // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
+
+ /* Completeness */
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 766266d..037a71e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -112,7 +112,8 @@
public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25;
// Freeform windows are showing in desktop mode
public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26;
-
+ // Device dreaming state
+ public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27;
@Retention(RetentionPolicy.SOURCE)
@IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -141,7 +142,8 @@
SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
SYSUI_STATE_IMMERSIVE_MODE,
SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING,
- SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE
+ SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE,
+ SYSUI_STATE_DEVICE_DREAMING
})
public @interface SystemUiStateFlags {}
@@ -179,6 +181,7 @@
str.add((flags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0 ? "vis_win_showing" : "");
str.add((flags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0
? "freeform_active_in_desktop_mode" : "");
+ str.add((flags & SYSUI_STATE_DEVICE_DREAMING) != 0 ? "device_dreaming" : "");
return str.toString();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 1680b47..3a940e9 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -54,7 +54,6 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
-import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.Executor
@@ -309,15 +308,6 @@
resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat())
}
- /**
- * Dump information for debugging
- */
- fun dump(pw: PrintWriter) {
- pw.println(this)
- clock?.dump(pw)
- regionSampler?.dump(pw)
- }
-
@VisibleForTesting
internal fun listenForDozeAmount(scope: CoroutineScope): Job {
return scope.launch {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 71cd18d..8684019 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -45,6 +45,7 @@
import com.android.systemui.plugins.log.LogLevel;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.clocks.ClockRegistry;
+import com.android.systemui.shared.regionsampling.RegionSampler;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -88,7 +89,9 @@
private final ClockRegistry.ClockChangeListener mClockChangedListener;
private ViewGroup mStatusArea;
- // If set will replace keyguard_slice_view
+
+ // If the SMARTSPACE flag is set, keyguard_slice_view is replaced by the following views.
+ private View mWeatherView;
private View mSmartspaceView;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@@ -192,10 +195,17 @@
if (mSmartspaceController.isEnabled()) {
View ksv = mView.findViewById(R.id.keyguard_slice_view);
- int ksvIndex = mStatusArea.indexOfChild(ksv);
+ int viewIndex = mStatusArea.indexOfChild(ksv);
ksv.setVisibility(View.GONE);
- addSmartspaceView(ksvIndex);
+ // TODO(b/261757708): add content observer for the Settings toggle and add/remove
+ // weather according to the Settings.
+ if (mSmartspaceController.isDateWeatherDecoupled()) {
+ addWeatherView(viewIndex);
+ viewIndex += 1;
+ }
+
+ addSmartspaceView(viewIndex);
}
mSecureSettings.registerContentObserverForUser(
@@ -237,6 +247,18 @@
}
}
+ private void addWeatherView(int index) {
+ mWeatherView = mSmartspaceController.buildAndConnectWeatherView(mView);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ MATCH_PARENT, WRAP_CONTENT);
+ mStatusArea.addView(mWeatherView, index, lp);
+ int startPadding = getContext().getResources().getDimensionPixelSize(
+ R.dimen.below_clock_padding_start);
+ int endPadding = getContext().getResources().getDimensionPixelSize(
+ R.dimen.below_clock_padding_end);
+ mWeatherView.setPaddingRelative(startPadding, 0, endPadding, 0);
+ }
+
private void addSmartspaceView(int index) {
mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
@@ -424,6 +446,10 @@
if (clock != null) {
clock.dump(pw);
}
+ final RegionSampler regionSampler = mClockEventController.getRegionSampler();
+ if (regionSampler != null) {
+ regionSampler.dump(pw);
+ }
}
/** Gets the animations for the current clock. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 02776a2..ec8fa92 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -15,8 +15,6 @@
*/
package com.android.keyguard;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import android.app.Presentation;
import android.content.Context;
import android.graphics.Color;
@@ -37,9 +35,11 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
+import com.android.systemui.settings.DisplayTracker;
import java.util.concurrent.Executor;
@@ -53,6 +53,7 @@
private MediaRouter mMediaRouter = null;
private final DisplayManager mDisplayService;
+ private final DisplayTracker mDisplayTracker;
private final Lazy<NavigationBarController> mNavigationBarControllerLazy;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final Context mContext;
@@ -62,46 +63,43 @@
private final SparseArray<Presentation> mPresentations = new SparseArray<>();
- private final DisplayManager.DisplayListener mDisplayListener =
- new DisplayManager.DisplayListener() {
+ private final DisplayTracker.Callback mDisplayCallback =
+ new DisplayTracker.Callback() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ Trace.beginSection(
+ "KeyguardDisplayManager#onDisplayAdded(displayId=" + displayId + ")");
+ final Display display = mDisplayService.getDisplay(displayId);
+ if (mShowing) {
+ updateNavigationBarVisibility(displayId, false /* navBarVisible */);
+ showPresentation(display);
+ }
+ Trace.endSection();
+ }
- @Override
- public void onDisplayAdded(int displayId) {
- Trace.beginSection(
- "KeyguardDisplayManager#onDisplayAdded(displayId=" + displayId + ")");
- final Display display = mDisplayService.getDisplay(displayId);
- if (mShowing) {
- updateNavigationBarVisibility(displayId, false /* navBarVisible */);
- showPresentation(display);
- }
- Trace.endSection();
- }
-
- @Override
- public void onDisplayChanged(int displayId) {
-
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- Trace.beginSection(
- "KeyguardDisplayManager#onDisplayRemoved(displayId=" + displayId + ")");
- hidePresentation(displayId);
- Trace.endSection();
- }
- };
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ Trace.beginSection(
+ "KeyguardDisplayManager#onDisplayRemoved(displayId=" + displayId + ")");
+ hidePresentation(displayId);
+ Trace.endSection();
+ }
+ };
@Inject
public KeyguardDisplayManager(Context context,
Lazy<NavigationBarController> navigationBarControllerLazy,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
+ DisplayTracker displayTracker,
+ @Main Executor mainExecutor,
@UiBackground Executor uiBgExecutor) {
mContext = context;
mNavigationBarControllerLazy = navigationBarControllerLazy;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
uiBgExecutor.execute(() -> mMediaRouter = mContext.getSystemService(MediaRouter.class));
mDisplayService = mContext.getSystemService(DisplayManager.class);
- mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
+ mDisplayTracker = displayTracker;
+ mDisplayTracker.addDisplayChangeCallback(mDisplayCallback, mainExecutor);
}
private boolean isKeyguardShowable(Display display) {
@@ -109,7 +107,7 @@
if (DEBUG) Log.i(TAG, "Cannot show Keyguard on null display");
return false;
}
- if (display.getDisplayId() == DEFAULT_DISPLAY) {
+ if (display.getDisplayId() == mDisplayTracker.getDefaultDisplayId()) {
if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on the default display");
return false;
}
@@ -224,7 +222,7 @@
protected boolean updateDisplays(boolean showing) {
boolean changed = false;
if (showing) {
- final Display[] displays = mDisplayService.getDisplays();
+ final Display[] displays = mDisplayTracker.getAllDisplays();
for (Display display : displays) {
int displayId = display.getDisplayId();
updateNavigationBarVisibility(displayId, false /* navBarVisible */);
@@ -247,7 +245,7 @@
// term solution in R.
private void updateNavigationBarVisibility(int displayId, boolean navBarVisible) {
// Leave this task to {@link StatusBarKeyguardViewManager}
- if (displayId == DEFAULT_DISPLAY) return;
+ if (displayId == mDisplayTracker.getDefaultDisplayId()) return;
NavigationBarView navBarView = mNavigationBarControllerLazy.get()
.getNavigationBarView(displayId);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5fd2fab..9f07a20 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -92,6 +92,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.Utils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -999,8 +1000,10 @@
private Drawable findUserIcon(int userId) {
Bitmap userIcon = UserManager.get(mView.getContext()).getUserIcon(userId);
if (userIcon != null) {
- return new BitmapDrawable(userIcon);
+ return CircleFramedDrawable.getInstance(mView.getContext(),
+ userIcon);
}
+
return UserIcons.getDefaultUserIcon(mResources, userId, false);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index 0b2b121..e3de8c7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -17,7 +17,6 @@
package com.android.keyguard;
import static android.app.slice.Slice.HINT_LIST_ITEM;
-import static android.view.Display.DEFAULT_DISPLAY;
import android.app.PendingIntent;
import android.net.Uri;
@@ -43,6 +42,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.ViewController;
@@ -64,6 +64,7 @@
private final ConfigurationController mConfigurationController;
private final TunerService mTunerService;
private final DumpManager mDumpManager;
+ private final DisplayTracker mDisplayTracker;
private int mDisplayId;
private LiveData<Slice> mLiveData;
private Uri mKeyguardSliceUri;
@@ -108,12 +109,14 @@
ActivityStarter activityStarter,
ConfigurationController configurationController,
TunerService tunerService,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ DisplayTracker displayTracker) {
super(keyguardSliceView);
mActivityStarter = activityStarter;
mConfigurationController = configurationController;
mTunerService = tunerService;
mDumpManager = dumpManager;
+ mDisplayTracker = displayTracker;
}
@Override
@@ -124,7 +127,7 @@
}
mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI);
// Make sure we always have the most current slice
- if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) {
+ if (mDisplayId == mDisplayTracker.getDefaultDisplayId() && mLiveData != null) {
mLiveData.observeForever(mObserver);
}
mConfigurationController.addCallback(mConfigurationListener);
@@ -137,7 +140,7 @@
@Override
protected void onViewDetached() {
// TODO(b/117344873) Remove below work around after this issue be fixed.
- if (mDisplayId == DEFAULT_DISPLAY) {
+ if (mDisplayId == mDisplayTracker.getDefaultDisplayId()) {
mLiveData.removeObserver(mObserver);
}
mTunerService.removeTunable(mTunable);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 3581be4..54886c3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -26,7 +26,6 @@
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_PERMANENT;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED;
import static android.hardware.biometrics.BiometricConstants.LockoutMode;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.hardware.biometrics.BiometricSourceType.FACE;
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -352,7 +351,6 @@
private final Executor mBackgroundExecutor;
private final SensorPrivacyManager mSensorPrivacyManager;
private final ActiveUnlockConfig mActiveUnlockConfig;
- private final PowerManager mPowerManager;
private final IDreamManager mDreamManager;
private final TelephonyManager mTelephonyManager;
@Nullable
@@ -360,7 +358,6 @@
@Nullable
private final FaceManager mFaceManager;
private final LockPatternUtils mLockPatternUtils;
- private final boolean mWakeOnFingerprintAcquiredStart;
@VisibleForTesting
@DevicePostureController.DevicePostureInt
protected int mConfigFaceAuthSupportedPosture;
@@ -884,11 +881,6 @@
private void handleFingerprintAcquired(
@BiometricFingerprintConstants.FingerprintAcquired int acquireInfo) {
Assert.isMainThread();
- if (mWakeOnFingerprintAcquiredStart && acquireInfo == FINGERPRINT_ACQUIRED_START) {
- mPowerManager.wakeUp(
- SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_BIOMETRIC,
- "com.android.systemui.keyguard:FINGERPRINT_ACQUIRED_START");
- }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1945,6 +1937,11 @@
}
}
mGoingToSleep = true;
+ // Resetting assistant visibility state as the device is going to sleep now.
+ // TaskStackChangeListener gets triggered a little late when we transition to AoD,
+ // which results in face auth running once on AoD.
+ mAssistantVisible = false;
+ mLogger.d("Started going to sleep, mGoingToSleep=true, mAssistantVisible=false");
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_GOING_TO_SLEEP);
}
@@ -2050,7 +2047,6 @@
UiEventLogger uiEventLogger,
// This has to be a provider because SessionTracker depends on KeyguardUpdateMonitor :(
Provider<SessionTracker> sessionTrackerProvider,
- PowerManager powerManager,
TrustManager trustManager,
SubscriptionManager subscriptionManager,
UserManager userManager,
@@ -2087,7 +2083,6 @@
mLogger = logger;
mUiEventLogger = uiEventLogger;
mSessionTrackerProvider = sessionTrackerProvider;
- mPowerManager = powerManager;
mTrustManager = trustManager;
mUserManager = userManager;
mDreamManager = dreamManager;
@@ -2098,8 +2093,6 @@
mFpm = fingerprintManager;
mFaceManager = faceManager;
mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
- mWakeOnFingerprintAcquiredStart = context.getResources()
- .getBoolean(com.android.internal.R.bool.kg_wake_on_acquire_start);
mFaceAcquiredInfoIgnoreList = Arrays.stream(
mContext.getResources().getIntArray(
R.array.config_face_acquire_device_entry_ignorelist))
@@ -3342,7 +3335,8 @@
/**
* Handle {@link #MSG_KEYGUARD_RESET}
*/
- private void handleKeyguardReset() {
+ @VisibleForTesting
+ protected void handleKeyguardReset() {
mLogger.d("handleKeyguardReset");
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
FACE_AUTH_UPDATED_KEYGUARD_RESET);
@@ -3882,7 +3876,6 @@
pw.println(" getUserHasTrust()=" + getUserHasTrust(getCurrentUser()));
pw.println(" getUserUnlockedWithBiometric()="
+ getUserUnlockedWithBiometric(getCurrentUser()));
- pw.println(" mWakeOnFingerprintAcquiredStart=" + mWakeOnFingerprintAcquiredStart);
pw.println(" SIM States:");
for (SimData data : mSimDatas.values()) {
pw.println(" " + data.toString());
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 1322f16..8071a5d 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -429,6 +429,7 @@
pw.println(" mStatusBarState: " + StatusBarState.toString(mStatusBarState));
pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
+ pw.println(" mDefaultPaddingPx: " + mDefaultPaddingPx);
if (mView != null) {
mView.dump(pw, args);
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
index 0cbf8bc..5ad21df 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerComponent.java
@@ -20,13 +20,13 @@
import com.android.keyguard.KeyguardHostViewController;
import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import dagger.BindsInstance;
import dagger.Subcomponent;
/**
- * Dagger Subcomponent for the {@link KeyguardBouncer}.
+ * Dagger Subcomponent for the {@link PrimaryBouncerInteractor}.
*/
@Subcomponent(modules = {KeyguardBouncerModule.class})
@KeyguardBouncerScope
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index ef067b8..cb7a0a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -29,7 +29,7 @@
import com.android.systemui.R;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
+import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import java.util.Optional;
@@ -39,7 +39,7 @@
import dagger.Provides;
/**
- * Module to create and access view related to the {@link KeyguardBouncer}.
+ * Module to create and access view related to the {@link PrimaryBouncerInteractor}.
*/
@Module
public interface KeyguardBouncerModule {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index e6f559b..71f98fa 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -36,10 +36,10 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.hardware.display.DisplayManager;
import android.hardware.graphics.common.AlphaInterpretation;
import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.SystemProperties;
import android.os.Trace;
import android.provider.Settings.Secure;
@@ -76,6 +76,7 @@
import com.android.systemui.decor.RoundedCornerDecorProviderFactory;
import com.android.systemui.decor.RoundedCornerResDelegate;
import com.android.systemui.qs.SettingObserver;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.tuner.TunerService;
@@ -120,7 +121,7 @@
R.id.display_cutout_bottom
};
- private DisplayManager mDisplayManager;
+ private DisplayTracker mDisplayTracker;
@VisibleForTesting
protected boolean mIsRegistered;
private final Context mContext;
@@ -128,7 +129,7 @@
private final TunerService mTunerService;
private final SecureSettings mSecureSettings;
@VisibleForTesting
- DisplayManager.DisplayListener mDisplayListener;
+ DisplayTracker.Callback mDisplayListener;
private CameraAvailabilityListener mCameraListener;
private final UserTracker mUserTracker;
private final PrivacyDotViewController mDotViewController;
@@ -302,6 +303,7 @@
SecureSettings secureSettings,
TunerService tunerService,
UserTracker userTracker,
+ DisplayTracker displayTracker,
PrivacyDotViewController dotViewController,
ThreadFactory threadFactory,
PrivacyDotDecorProviderFactory dotFactory,
@@ -311,6 +313,7 @@
mSecureSettings = secureSettings;
mTunerService = tunerService;
mUserTracker = userTracker;
+ mDisplayTracker = displayTracker;
mDotViewController = dotViewController;
mThreadFactory = threadFactory;
mDotFactory = dotFactory;
@@ -376,7 +379,6 @@
private void startOnScreenDecorationsThread() {
Trace.beginSection("ScreenDecorations#startOnScreenDecorationsThread");
mWindowManager = mContext.getSystemService(WindowManager.class);
- mDisplayManager = mContext.getSystemService(DisplayManager.class);
mContext.getDisplay().getDisplayInfo(mDisplayInfo);
mRotation = mDisplayInfo.rotation;
mDisplayMode = mDisplayInfo.getMode();
@@ -393,17 +395,7 @@
setupDecorations();
setupCameraListener();
- mDisplayListener = new DisplayManager.DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {
- // do nothing
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- // do nothing
- }
-
+ mDisplayListener = new DisplayTracker.Callback() {
@Override
public void onDisplayChanged(int displayId) {
mContext.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -474,8 +466,7 @@
}
}
};
-
- mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+ mDisplayTracker.addDisplayChangeCallback(mDisplayListener, new HandlerExecutor(mHandler));
updateConfiguration();
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index 4c92598..ddac25b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -36,7 +36,6 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
-import android.view.Display;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -50,6 +49,7 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.CommandQueue;
@@ -180,6 +180,7 @@
private final Context mContext;
private final UserTracker mUserTracker;
private final Optional<Recents> mRecentsOptional;
+ private final DisplayTracker mDisplayTracker;
private Locale mLocale;
private final AccessibilityManager mA11yManager;
private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -194,11 +195,13 @@
NotificationShadeWindowController notificationShadeController,
ShadeController shadeController,
Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
- Optional<Recents> recentsOptional) {
+ Optional<Recents> recentsOptional,
+ DisplayTracker displayTracker) {
mContext = context;
mUserTracker = userTracker;
mShadeController = shadeController;
mRecentsOptional = recentsOptional;
+ mDisplayTracker = displayTracker;
mReceiver = new SystemActionsBroadcastReceiver();
mLocale = mContext.getResources().getConfiguration().getLocales().get(0);
mA11yManager = (AccessibilityManager) mContext.getSystemService(
@@ -207,7 +210,8 @@
// Saving in instance variable since to prevent GC since
// NotificationShadeWindowController.registerCallback() only keeps weak references.
mNotificationShadeCallback =
- (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded) ->
+ (keyguardShowing, keyguardOccluded, bouncerShowing, mDozing, panelExpanded,
+ isDreaming) ->
registerOrUnregisterDismissNotificationShadeAction();
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
}
@@ -522,7 +526,7 @@
private void handleAccessibilityButton() {
AccessibilityManager.getInstance(mContext).notifyAccessibilityButtonClicked(
- Display.DEFAULT_DISPLAY);
+ mDisplayTracker.getDefaultDisplayId());
}
private void handleAccessibilityButtonChooser() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index ab11fce..b3574bf 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -39,6 +39,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import java.io.PrintWriter;
@@ -62,6 +63,7 @@
private final AccessibilityManager mAccessibilityManager;
private final CommandQueue mCommandQueue;
private final OverviewProxyService mOverviewProxyService;
+ private final DisplayTracker mDisplayTracker;
private WindowMagnificationConnectionImpl mWindowMagnificationConnectionImpl;
private SysUiState mSysUiState;
@@ -102,7 +104,8 @@
@Inject
public WindowMagnification(Context context, @Main Handler mainHandler,
CommandQueue commandQueue, ModeSwitchesController modeSwitchesController,
- SysUiState sysUiState, OverviewProxyService overviewProxyService) {
+ SysUiState sysUiState, OverviewProxyService overviewProxyService,
+ DisplayTracker displayTracker) {
mContext = context;
mHandler = mainHandler;
mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
@@ -110,6 +113,7 @@
mModeSwitchesController = modeSwitchesController;
mSysUiState = sysUiState;
mOverviewProxyService = overviewProxyService;
+ mDisplayTracker = displayTracker;
mMagnificationControllerSupplier = new ControllerSupplier(context,
mHandler, this, context.getSystemService(DisplayManager.class), sysUiState);
}
@@ -130,14 +134,14 @@
private void updateSysUiStateFlag() {
//TODO(b/187510533): support multi-display once SysuiState supports it.
final WindowMagnificationController controller =
- mMagnificationControllerSupplier.valueAt(Display.DEFAULT_DISPLAY);
+ mMagnificationControllerSupplier.valueAt(mDisplayTracker.getDefaultDisplayId());
if (controller != null) {
controller.updateSysUIStateFlag();
} else {
// The instance is initialized when there is an IPC request. Considering
// self-crash cases, we need to reset the flag in such situation.
mSysUiState.setFlag(SYSUI_STATE_MAGNIFICATION_OVERLAP, false)
- .commitUpdate(Display.DEFAULT_DISPLAY);
+ .commitUpdate(mDisplayTracker.getDefaultDisplayId());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index da2e28c5..1ea173e 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -1,7 +1,5 @@
package com.android.systemui.assist;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED;
@@ -35,6 +33,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -122,6 +121,7 @@
protected final Lazy<SysUiState> mSysUiState;
protected final AssistLogger mAssistLogger;
private final UserTracker mUserTracker;
+ private final DisplayTracker mDisplayTracker;
private final SecureSettings mSecureSettings;
private final DeviceProvisionedController mDeviceProvisionedController;
@@ -141,6 +141,7 @@
AssistLogger assistLogger,
@Main Handler uiHandler,
UserTracker userTracker,
+ DisplayTracker displayTracker,
SecureSettings secureSettings) {
mContext = context;
mDeviceProvisionedController = controller;
@@ -150,6 +151,7 @@
mPhoneStateMonitor = phoneStateMonitor;
mAssistLogger = assistLogger;
mUserTracker = userTracker;
+ mDisplayTracker = displayTracker;
mSecureSettings = secureSettings;
registerVoiceInteractionSessionListener();
@@ -214,7 +216,7 @@
.setFlag(
SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
hints.getBoolean(CONSTRAINED_KEY, false))
- .commitUpdate(DEFAULT_DISPLAY);
+ .commitUpdate(mDisplayTracker.getDefaultDisplayId());
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 68e1f72..febf75e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -847,7 +847,7 @@
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
windowFlags,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 4b57d45..04a2689 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -55,11 +55,11 @@
private val fadeDuration = 83L
private val retractDuration = 400L
private var alphaInDuration: Long = 0
- private var unlockedRippleInProgress: Boolean = false
private val dwellShader = DwellRippleShader()
private val dwellPaint = Paint()
private val rippleShader = RippleShader()
private val ripplePaint = Paint()
+ private var unlockedRippleAnimator: AnimatorSet? = null
private var fadeDwellAnimator: Animator? = null
private var retractDwellAnimator: Animator? = null
private var dwellPulseOutAnimator: Animator? = null
@@ -205,7 +205,7 @@
* Plays a ripple animation that grows to the dwellRadius with distortion.
*/
fun startDwellRipple(isDozing: Boolean) {
- if (unlockedRippleInProgress || dwellPulseOutAnimator?.isRunning == true) {
+ if (unlockedRippleAnimator?.isRunning == true || dwellPulseOutAnimator?.isRunning == true) {
return
}
@@ -262,9 +262,7 @@
* Ripple that bursts outwards from the position of the sensor to the edges of the screen
*/
fun startUnlockedRipple(onAnimationEnd: Runnable?) {
- if (unlockedRippleInProgress) {
- return // Ignore if ripple effect is already playing
- }
+ unlockedRippleAnimator?.cancel()
val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
interpolator = Interpolators.LINEAR_OUT_SLOW_IN
@@ -289,14 +287,13 @@
}
}
- val animatorSet = AnimatorSet().apply {
+ unlockedRippleAnimator = AnimatorSet().apply {
playTogether(
rippleAnimator,
alphaInAnimator
)
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator?) {
- unlockedRippleInProgress = true
rippleShader.rippleFill = false
drawRipple = true
visibility = VISIBLE
@@ -304,13 +301,13 @@
override fun onAnimationEnd(animation: Animator?) {
onAnimationEnd?.run()
- unlockedRippleInProgress = false
drawRipple = false
visibility = GONE
+ unlockedRippleAnimator = null
}
})
}
- animatorSet.start()
+ unlockedRippleAnimator?.start()
}
fun resetRippleAlpha() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 6f594d5..c799e91 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -54,12 +54,18 @@
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.PrintWriter
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
private const val TAG = "SideFpsController"
@@ -79,6 +85,9 @@
displayManager: DisplayManager,
@Main private val mainExecutor: DelayableExecutor,
@Main private val handler: Handler,
+ private val alternateBouncerInteractor: AlternateBouncerInteractor,
+ @Application private val scope: CoroutineScope,
+ private val featureFlags: FeatureFlags,
dumpManager: DumpManager
) : Dumpable {
val requests: HashSet<SideFpsUiRequestSource> = HashSet()
@@ -168,9 +177,26 @@
}
)
overviewProxyService.addCallback(overviewProxyListener)
+ listenForAlternateBouncerVisibility()
+
dumpManager.registerDumpable(this)
}
+ private fun listenForAlternateBouncerVisibility() {
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true)
+ if (featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER)) {
+ scope.launch {
+ alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
+ if (isVisible) {
+ show(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
+ } else {
+ hide(SideFpsUiRequestSource.ALTERNATE_BOUNCER)
+ }
+ }
+ }
+ }
+ }
+
/** Shows the side fps overlay if not already shown. */
fun show(request: SideFpsUiRequestSource) {
requests.add(request)
@@ -423,4 +449,5 @@
AUTO_SHOW,
/** Pin, pattern or password bouncer */
PRIMARY_BOUNCER,
+ ALTERNATE_BOUNCER
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index 63a1b76..d072ec7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -32,7 +32,6 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -149,21 +148,6 @@
}
}
- private val mPrimaryBouncerExpansionCallback: PrimaryBouncerExpansionCallback =
- object : PrimaryBouncerExpansionCallback {
- override fun onExpansionChanged(expansion: Float) {
- inputBouncerHiddenAmount = expansion
- updateAlpha()
- updatePauseAuth()
- }
-
- override fun onVisibilityChanged(isVisible: Boolean) {
- updateBouncerHiddenAmount()
- updateAlpha()
- updatePauseAuth()
- }
- }
-
private val configurationListener: ConfigurationController.ConfigurationListener =
object : ConfigurationController.ConfigurationListener {
override fun onUiModeChanged() {
@@ -315,14 +299,6 @@
statusBarState = statusBarStateController.state
qsExpansion = keyguardViewManager.qsExpansion
keyguardViewManager.addCallback(statusBarKeyguardViewManagerCallback)
- if (!isModernBouncerEnabled) {
- val bouncer = keyguardViewManager.primaryBouncer
- bouncer?.expansion?.let {
- mPrimaryBouncerExpansionCallback.onExpansionChanged(it)
- bouncer.addBouncerExpansionCallback(mPrimaryBouncerExpansionCallback)
- }
- updateBouncerHiddenAmount()
- }
configurationController.addCallback(configurationListener)
shadeExpansionStateManager.addExpansionListener(shadeExpansionListener)
updateScaleFactor()
@@ -352,11 +328,6 @@
}
activityLaunchAnimator.removeListener(activityLaunchAnimatorListener)
keyguardViewManager.removeCallback(statusBarKeyguardViewManagerCallback)
- if (!isModernBouncerEnabled) {
- keyguardViewManager.primaryBouncer?.removeBouncerExpansionCallback(
- mPrimaryBouncerExpansionCallback
- )
- }
}
override fun dump(pw: PrintWriter, args: Array<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index 805a20a..1c26841 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -18,7 +18,6 @@
import static android.content.ClipDescription.CLASSIFICATION_COMPLETE;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN;
@@ -29,7 +28,6 @@
import android.content.ClipboardManager;
import android.content.Context;
import android.os.SystemProperties;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.Log;
@@ -37,9 +35,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.CoreStartable;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.util.DeviceConfigProxy;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -59,42 +54,28 @@
"com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY";
private final Context mContext;
- private final DeviceConfigProxy mDeviceConfig;
private final Provider<ClipboardOverlayController> mOverlayProvider;
- private final ClipboardOverlayControllerLegacyFactory mOverlayFactory;
private final ClipboardToast mClipboardToast;
private final ClipboardManager mClipboardManager;
private final UiEventLogger mUiEventLogger;
- private final FeatureFlags mFeatureFlags;
- private boolean mUsingNewOverlay;
private ClipboardOverlay mClipboardOverlay;
@Inject
- public ClipboardListener(Context context, DeviceConfigProxy deviceConfigProxy,
+ public ClipboardListener(Context context,
Provider<ClipboardOverlayController> clipboardOverlayControllerProvider,
- ClipboardOverlayControllerLegacyFactory overlayFactory,
ClipboardToast clipboardToast,
ClipboardManager clipboardManager,
- UiEventLogger uiEventLogger,
- FeatureFlags featureFlags) {
+ UiEventLogger uiEventLogger) {
mContext = context;
- mDeviceConfig = deviceConfigProxy;
mOverlayProvider = clipboardOverlayControllerProvider;
- mOverlayFactory = overlayFactory;
mClipboardToast = clipboardToast;
mClipboardManager = clipboardManager;
mUiEventLogger = uiEventLogger;
- mFeatureFlags = featureFlags;
-
- mUsingNewOverlay = mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR);
}
@Override
public void start() {
- if (mDeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, true)) {
- mClipboardManager.addPrimaryClipChangedListener(this);
- }
+ mClipboardManager.addPrimaryClipChangedListener(this);
}
@Override
@@ -120,14 +101,8 @@
return;
}
- boolean enabled = mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR);
- if (mClipboardOverlay == null || enabled != mUsingNewOverlay) {
- mUsingNewOverlay = enabled;
- if (enabled) {
- mClipboardOverlay = mOverlayProvider.get();
- } else {
- mClipboardOverlay = mOverlayFactory.create(mContext);
- }
+ if (mClipboardOverlay == null) {
+ mClipboardOverlay = mOverlayProvider.get();
mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource);
} else {
mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index f97d6af..8c8ee8a 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -17,7 +17,6 @@
package com.android.systemui.clipboardoverlay;
import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
@@ -72,6 +71,7 @@
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.screenshot.TimeoutHandler;
+import com.android.systemui.settings.DisplayTracker;
import java.io.IOException;
import java.util.Optional;
@@ -96,6 +96,7 @@
private final ClipboardLogger mClipboardLogger;
private final BroadcastDispatcher mBroadcastDispatcher;
private final DisplayManager mDisplayManager;
+ private final DisplayTracker mDisplayTracker;
private final ClipboardOverlayWindow mWindow;
private final TimeoutHandler mTimeoutHandler;
private final ClipboardOverlayUtils mClipboardUtils;
@@ -186,9 +187,11 @@
FeatureFlags featureFlags,
ClipboardOverlayUtils clipboardUtils,
@Background Executor bgExecutor,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ DisplayTracker displayTracker) {
mBroadcastDispatcher = broadcastDispatcher;
mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
+ mDisplayTracker = displayTracker;
final Context displayContext = context.createDisplayContext(getDefaultDisplay());
mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
@@ -514,7 +517,7 @@
}
private Display getDefaultDisplay() {
- return mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+ return mDisplayManager.getDisplay(mDisplayTracker.getDefaultDisplayId());
}
static class ClipboardLogger {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java
deleted file mode 100644
index 3a040829..0000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacy.java
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- * Copyright (C) 2021 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.clipboardoverlay;
-
-import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISSED_OTHER;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_EDIT_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHARE_TAPPED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
-import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
-
-import static java.util.Objects.requireNonNull;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.annotation.MainThread;
-import android.app.ICompatCameraControlCallback;
-import android.app.RemoteAction;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Insets;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.drawable.Icon;
-import android.hardware.display.DisplayManager;
-import android.hardware.input.InputManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Looper;
-import android.provider.DeviceConfig;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.util.Size;
-import android.util.TypedValue;
-import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.Gravity;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.InputMonitor;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
-import android.view.textclassifier.TextClassification;
-import android.view.textclassifier.TextClassificationManager;
-import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLinks;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.core.view.ViewCompat;
-import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.policy.PhoneWindow;
-import com.android.systemui.R;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.screenshot.DraggableConstraintLayout;
-import com.android.systemui.screenshot.FloatingWindowUtil;
-import com.android.systemui.screenshot.OverlayActionChip;
-import com.android.systemui.screenshot.TimeoutHandler;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * Controls state and UI for the overlay that appears when something is added to the clipboard
- */
-public class ClipboardOverlayControllerLegacy implements ClipboardListener.ClipboardOverlay {
- private static final String TAG = "ClipboardOverlayCtrlr";
- private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
-
- /** Constants for screenshot/copy deconflicting */
- public static final String SCREENSHOT_ACTION = "com.android.systemui.SCREENSHOT";
- public static final String SELF_PERMISSION = "com.android.systemui.permission.SELF";
- public static final String COPY_OVERLAY_ACTION = "com.android.systemui.COPY";
-
- private static final String EXTRA_EDIT_SOURCE_CLIPBOARD = "edit_source_clipboard";
-
- private static final int CLIPBOARD_DEFAULT_TIMEOUT_MILLIS = 6000;
- private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
- private static final int FONT_SEARCH_STEP_PX = 4;
-
- private final Context mContext;
- private final ClipboardLogger mClipboardLogger;
- private final BroadcastDispatcher mBroadcastDispatcher;
- private final DisplayManager mDisplayManager;
- private final DisplayMetrics mDisplayMetrics;
- private final WindowManager mWindowManager;
- private final WindowManager.LayoutParams mWindowLayoutParams;
- private final PhoneWindow mWindow;
- private final TimeoutHandler mTimeoutHandler;
- private final AccessibilityManager mAccessibilityManager;
- private final TextClassifier mTextClassifier;
-
- private final DraggableConstraintLayout mView;
- private final View mClipboardPreview;
- private final ImageView mImagePreview;
- private final TextView mTextPreview;
- private final TextView mHiddenPreview;
- private final View mPreviewBorder;
- private final OverlayActionChip mEditChip;
- private final OverlayActionChip mShareChip;
- private final OverlayActionChip mRemoteCopyChip;
- private final View mActionContainerBackground;
- private final View mDismissButton;
- private final LinearLayout mActionContainer;
- private final ArrayList<OverlayActionChip> mActionChips = new ArrayList<>();
-
- private Runnable mOnSessionCompleteListener;
-
- private InputMonitor mInputMonitor;
- private InputEventReceiver mInputEventReceiver;
-
- private BroadcastReceiver mCloseDialogsReceiver;
- private BroadcastReceiver mScreenshotReceiver;
-
- private boolean mBlockAttach = false;
- private Animator mExitAnimator;
- private Animator mEnterAnimator;
- private final int mOrientation;
- private boolean mKeyboardVisible;
-
-
- public ClipboardOverlayControllerLegacy(Context context,
- BroadcastDispatcher broadcastDispatcher,
- BroadcastSender broadcastSender,
- TimeoutHandler timeoutHandler, UiEventLogger uiEventLogger) {
- mBroadcastDispatcher = broadcastDispatcher;
- mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
- final Context displayContext = context.createDisplayContext(getDefaultDisplay());
- mContext = displayContext.createWindowContext(TYPE_SCREENSHOT, null);
-
- mClipboardLogger = new ClipboardLogger(uiEventLogger);
-
- mAccessibilityManager = AccessibilityManager.getInstance(mContext);
- mTextClassifier = requireNonNull(context.getSystemService(TextClassificationManager.class))
- .getTextClassifier();
-
- mWindowManager = mContext.getSystemService(WindowManager.class);
-
- mDisplayMetrics = new DisplayMetrics();
- mContext.getDisplay().getRealMetrics(mDisplayMetrics);
-
- mTimeoutHandler = timeoutHandler;
- mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
-
- // Setup the window that we are going to use
- mWindowLayoutParams = FloatingWindowUtil.getFloatingWindowParams();
- mWindowLayoutParams.setTitle("ClipboardOverlay");
-
- mWindow = FloatingWindowUtil.getFloatingWindow(mContext);
- mWindow.setWindowManager(mWindowManager, null, null);
-
- setWindowFocusable(false);
-
- mView = (DraggableConstraintLayout)
- LayoutInflater.from(mContext).inflate(R.layout.clipboard_overlay_legacy, null);
- mActionContainerBackground =
- requireNonNull(mView.findViewById(R.id.actions_container_background));
- mActionContainer = requireNonNull(mView.findViewById(R.id.actions));
- mClipboardPreview = requireNonNull(mView.findViewById(R.id.clipboard_preview));
- mImagePreview = requireNonNull(mView.findViewById(R.id.image_preview));
- mTextPreview = requireNonNull(mView.findViewById(R.id.text_preview));
- mHiddenPreview = requireNonNull(mView.findViewById(R.id.hidden_preview));
- mPreviewBorder = requireNonNull(mView.findViewById(R.id.preview_border));
- mEditChip = requireNonNull(mView.findViewById(R.id.edit_chip));
- mShareChip = requireNonNull(mView.findViewById(R.id.share_chip));
- mRemoteCopyChip = requireNonNull(mView.findViewById(R.id.remote_copy_chip));
- mEditChip.setAlpha(1);
- mShareChip.setAlpha(1);
- mRemoteCopyChip.setAlpha(1);
- mDismissButton = requireNonNull(mView.findViewById(R.id.dismiss_button));
-
- mShareChip.setContentDescription(mContext.getString(com.android.internal.R.string.share));
- mView.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
- @Override
- public void onInteraction() {
- mTimeoutHandler.resetTimeout();
- }
-
- @Override
- public void onSwipeDismissInitiated(Animator animator) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
- mExitAnimator = animator;
- }
-
- @Override
- public void onDismissComplete() {
- hideImmediate();
- }
- });
-
- mTextPreview.getViewTreeObserver().addOnPreDrawListener(() -> {
- int availableHeight = mTextPreview.getHeight()
- - (mTextPreview.getPaddingTop() + mTextPreview.getPaddingBottom());
- mTextPreview.setMaxLines(availableHeight / mTextPreview.getLineHeight());
- return true;
- });
-
- mDismissButton.setOnClickListener(view -> {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
- animateOut();
- });
-
- mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
- mRemoteCopyChip.setIcon(
- Icon.createWithResource(mContext, R.drawable.ic_baseline_devices_24), true);
- mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
- mOrientation = mContext.getResources().getConfiguration().orientation;
-
- attachWindow();
- withWindowAttached(() -> {
- mWindow.setContentView(mView);
- WindowInsets insets = mWindowManager.getCurrentWindowMetrics().getWindowInsets();
- mKeyboardVisible = insets.isVisible(WindowInsets.Type.ime());
- updateInsets(insets);
- mWindow.peekDecorView().getViewTreeObserver().addOnGlobalLayoutListener(
- new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- WindowInsets insets =
- mWindowManager.getCurrentWindowMetrics().getWindowInsets();
- boolean keyboardVisible = insets.isVisible(WindowInsets.Type.ime());
- if (keyboardVisible != mKeyboardVisible) {
- mKeyboardVisible = keyboardVisible;
- updateInsets(insets);
- }
- }
- });
- mWindow.peekDecorView().getViewRootImpl().setActivityConfigCallback(
- new ViewRootImpl.ActivityConfigCallback() {
- @Override
- public void onConfigurationChanged(Configuration overrideConfig,
- int newDisplayId) {
- if (mContext.getResources().getConfiguration().orientation
- != mOrientation) {
- mClipboardLogger.logSessionComplete(
- CLIPBOARD_OVERLAY_DISMISSED_OTHER);
- hideImmediate();
- }
- }
-
- @Override
- public void requestCompatCameraControl(
- boolean showControl, boolean transformationApplied,
- ICompatCameraControlCallback callback) {
- Log.w(TAG, "unexpected requestCompatCameraControl call");
- }
- });
- });
-
- mTimeoutHandler.setOnTimeoutRunnable(() -> {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TIMED_OUT);
- animateOut();
- });
-
- mCloseDialogsReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
- animateOut();
- }
- }
- };
-
- mBroadcastDispatcher.registerReceiver(mCloseDialogsReceiver,
- new IntentFilter(ACTION_CLOSE_SYSTEM_DIALOGS));
- mScreenshotReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (SCREENSHOT_ACTION.equals(intent.getAction())) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
- animateOut();
- }
- }
- };
-
- mBroadcastDispatcher.registerReceiver(mScreenshotReceiver,
- new IntentFilter(SCREENSHOT_ACTION), null, null, Context.RECEIVER_EXPORTED,
- SELF_PERMISSION);
- monitorOutsideTouches();
-
- Intent copyIntent = new Intent(COPY_OVERLAY_ACTION);
- // Set package name so the system knows it's safe
- copyIntent.setPackage(mContext.getPackageName());
- broadcastSender.sendBroadcast(copyIntent, SELF_PERMISSION);
- }
-
- @Override // ClipboardListener.ClipboardOverlay
- public void setClipData(ClipData clipData, String clipSource) {
- if (mExitAnimator != null && mExitAnimator.isRunning()) {
- mExitAnimator.cancel();
- }
- reset();
- String accessibilityAnnouncement;
-
- boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null
- && clipData.getDescription().getExtras()
- .getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
- if (clipData == null || clipData.getItemCount() == 0) {
- showTextPreview(
- mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
- mTextPreview);
- accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
- } else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
- ClipData.Item item = clipData.getItemAt(0);
- if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
- if (item.getTextLinks() != null) {
- AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
- }
- }
- if (isSensitive) {
- showEditableText(
- mContext.getResources().getString(R.string.clipboard_asterisks), true);
- } else {
- showEditableText(item.getText(), false);
- }
- showShareChip(clipData);
- accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied);
- } else if (clipData.getItemAt(0).getUri() != null) {
- if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) {
- showShareChip(clipData);
- accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied);
- } else {
- accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
- }
- } else {
- showTextPreview(
- mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
- mTextPreview);
- accessibilityAnnouncement = mContext.getString(R.string.clipboard_content_copied);
- }
- Intent remoteCopyIntent = IntentCreator.getRemoteCopyIntent(clipData, mContext);
- // Only show remote copy if it's available.
- PackageManager packageManager = mContext.getPackageManager();
- if (packageManager.resolveActivity(
- remoteCopyIntent, PackageManager.ResolveInfoFlags.of(0)) != null) {
- mRemoteCopyChip.setContentDescription(
- mContext.getString(R.string.clipboard_send_nearby_description));
- mRemoteCopyChip.setVisibility(View.VISIBLE);
- mRemoteCopyChip.setOnClickListener((v) -> {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED);
- mContext.startActivity(remoteCopyIntent);
- animateOut();
- });
- mActionContainerBackground.setVisibility(View.VISIBLE);
- } else {
- mRemoteCopyChip.setVisibility(View.GONE);
- }
- withWindowAttached(() -> {
- if (mEnterAnimator == null || !mEnterAnimator.isRunning()) {
- mView.post(this::animateIn);
- }
- mView.announceForAccessibility(accessibilityAnnouncement);
- });
- mTimeoutHandler.resetTimeout();
- }
-
- @Override // ClipboardListener.ClipboardOverlay
- public void setOnSessionCompleteListener(Runnable runnable) {
- mOnSessionCompleteListener = runnable;
- }
-
- private void classifyText(ClipData.Item item, String source) {
- ArrayList<RemoteAction> actions = new ArrayList<>();
- for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
- TextClassification classification = mTextClassifier.classifyText(
- item.getText(), link.getStart(), link.getEnd(), null);
- actions.addAll(classification.getActions());
- }
- mView.post(() -> {
- resetActionChips();
- if (actions.size() > 0) {
- mActionContainerBackground.setVisibility(View.VISIBLE);
- for (RemoteAction action : actions) {
- Intent targetIntent = action.getActionIntent().getIntent();
- ComponentName component = targetIntent.getComponent();
- if (component != null && !TextUtils.equals(source,
- component.getPackageName())) {
- OverlayActionChip chip = constructActionChip(action);
- mActionContainer.addView(chip);
- mActionChips.add(chip);
- break; // only show at most one action chip
- }
- }
- }
- });
- }
-
- private void showShareChip(ClipData clip) {
- mShareChip.setVisibility(View.VISIBLE);
- mActionContainerBackground.setVisibility(View.VISIBLE);
- mShareChip.setOnClickListener((v) -> shareContent(clip));
- }
-
- private OverlayActionChip constructActionChip(RemoteAction action) {
- OverlayActionChip chip = (OverlayActionChip) LayoutInflater.from(mContext).inflate(
- R.layout.overlay_action_chip, mActionContainer, false);
- chip.setText(action.getTitle());
- chip.setContentDescription(action.getTitle());
- chip.setIcon(action.getIcon(), false);
- chip.setPendingIntent(action.getActionIntent(), () -> {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
- animateOut();
- });
- chip.setAlpha(1);
- return chip;
- }
-
- private void monitorOutsideTouches() {
- InputManager inputManager = mContext.getSystemService(InputManager.class);
- mInputMonitor = inputManager.monitorGestureInput("clipboard overlay", 0);
- mInputEventReceiver = new InputEventReceiver(mInputMonitor.getInputChannel(),
- Looper.getMainLooper()) {
- @Override
- public void onInputEvent(InputEvent event) {
- if (event instanceof MotionEvent) {
- MotionEvent motionEvent = (MotionEvent) event;
- if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
- Region touchRegion = new Region();
-
- final Rect tmpRect = new Rect();
- mPreviewBorder.getBoundsOnScreen(tmpRect);
- tmpRect.inset(
- (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
- (int) FloatingWindowUtil.dpToPx(mDisplayMetrics,
- -SWIPE_PADDING_DP));
- touchRegion.op(tmpRect, Region.Op.UNION);
- mActionContainerBackground.getBoundsOnScreen(tmpRect);
- tmpRect.inset(
- (int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
- (int) FloatingWindowUtil.dpToPx(mDisplayMetrics,
- -SWIPE_PADDING_DP));
- touchRegion.op(tmpRect, Region.Op.UNION);
- mDismissButton.getBoundsOnScreen(tmpRect);
- touchRegion.op(tmpRect, Region.Op.UNION);
- if (!touchRegion.contains(
- (int) motionEvent.getRawX(), (int) motionEvent.getRawY())) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
- animateOut();
- }
- }
- }
- finishInputEvent(event, true /* handled */);
- }
- };
- }
-
- private void editImage(Uri uri) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
- mContext.startActivity(IntentCreator.getImageEditIntent(uri, mContext));
- animateOut();
- }
-
- private void editText() {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
- mContext.startActivity(IntentCreator.getTextEditorIntent(mContext));
- animateOut();
- }
-
- private void shareContent(ClipData clip) {
- mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SHARE_TAPPED);
- mContext.startActivity(IntentCreator.getShareIntent(clip, mContext));
- animateOut();
- }
-
- private void showSinglePreview(View v) {
- mTextPreview.setVisibility(View.GONE);
- mImagePreview.setVisibility(View.GONE);
- mHiddenPreview.setVisibility(View.GONE);
- v.setVisibility(View.VISIBLE);
- }
-
- private void showTextPreview(CharSequence text, TextView textView) {
- showSinglePreview(textView);
- final CharSequence truncatedText = text.subSequence(0, Math.min(500, text.length()));
- textView.setText(truncatedText);
- updateTextSize(truncatedText, textView);
-
- textView.addOnLayoutChangeListener(
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
- if (right - left != oldRight - oldLeft) {
- updateTextSize(truncatedText, textView);
- }
- });
- mEditChip.setVisibility(View.GONE);
- }
-
- private void updateTextSize(CharSequence text, TextView textView) {
- Paint paint = new Paint(textView.getPaint());
- Resources res = textView.getResources();
- float minFontSize = res.getDimensionPixelSize(R.dimen.clipboard_overlay_min_font);
- float maxFontSize = res.getDimensionPixelSize(R.dimen.clipboard_overlay_max_font);
- if (isOneWord(text) && fitsInView(text, textView, paint, minFontSize)) {
- // If the text is a single word and would fit within the TextView at the min font size,
- // find the biggest font size that will fit.
- float fontSizePx = minFontSize;
- while (fontSizePx + FONT_SEARCH_STEP_PX < maxFontSize
- && fitsInView(text, textView, paint, fontSizePx + FONT_SEARCH_STEP_PX)) {
- fontSizePx += FONT_SEARCH_STEP_PX;
- }
- // Need to turn off autosizing, otherwise setTextSize is a no-op.
- textView.setAutoSizeTextTypeWithDefaults(TextView.AUTO_SIZE_TEXT_TYPE_NONE);
- // It's possible to hit the max font size and not fill the width, so centering
- // horizontally looks better in this case.
- textView.setGravity(Gravity.CENTER);
- textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, (int) fontSizePx);
- } else {
- // Otherwise just stick with autosize.
- textView.setAutoSizeTextTypeUniformWithConfiguration((int) minFontSize,
- (int) maxFontSize, FONT_SEARCH_STEP_PX, TypedValue.COMPLEX_UNIT_PX);
- textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
- }
- }
-
- private static boolean fitsInView(CharSequence text, TextView textView, Paint paint,
- float fontSizePx) {
- paint.setTextSize(fontSizePx);
- float size = paint.measureText(text.toString());
- float availableWidth = textView.getWidth() - textView.getPaddingLeft()
- - textView.getPaddingRight();
- return size < availableWidth;
- }
-
- private static boolean isOneWord(CharSequence text) {
- return text.toString().split("\\s+", 2).length == 1;
- }
-
- private void showEditableText(CharSequence text, boolean hidden) {
- TextView textView = hidden ? mHiddenPreview : mTextPreview;
- showTextPreview(text, textView);
- View.OnClickListener listener = v -> editText();
- setAccessibilityActionToEdit(textView);
- if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON, false)) {
- mEditChip.setVisibility(View.VISIBLE);
- mActionContainerBackground.setVisibility(View.VISIBLE);
- mEditChip.setContentDescription(
- mContext.getString(R.string.clipboard_edit_text_description));
- mEditChip.setOnClickListener(listener);
- }
- textView.setOnClickListener(listener);
- }
-
- private boolean tryShowEditableImage(Uri uri, boolean isSensitive) {
- View.OnClickListener listener = v -> editImage(uri);
- ContentResolver resolver = mContext.getContentResolver();
- String mimeType = resolver.getType(uri);
- boolean isEditableImage = mimeType != null && mimeType.startsWith("image");
- if (isSensitive) {
- mHiddenPreview.setText(mContext.getString(R.string.clipboard_text_hidden));
- showSinglePreview(mHiddenPreview);
- if (isEditableImage) {
- mHiddenPreview.setOnClickListener(listener);
- setAccessibilityActionToEdit(mHiddenPreview);
- }
- } else if (isEditableImage) { // if the MIMEtype is image, try to load
- try {
- int size = mContext.getResources().getDimensionPixelSize(R.dimen.overlay_x_scale);
- // The width of the view is capped, height maintains aspect ratio, so allow it to be
- // taller if needed.
- Bitmap thumbnail = resolver.loadThumbnail(uri, new Size(size, size * 4), null);
- showSinglePreview(mImagePreview);
- mImagePreview.setImageBitmap(thumbnail);
- mImagePreview.setOnClickListener(listener);
- setAccessibilityActionToEdit(mImagePreview);
- } catch (IOException e) {
- Log.e(TAG, "Thumbnail loading failed", e);
- showTextPreview(
- mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
- mTextPreview);
- isEditableImage = false;
- }
- } else {
- showTextPreview(
- mContext.getResources().getString(R.string.clipboard_overlay_text_copied),
- mTextPreview);
- }
- if (isEditableImage && DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON, false)) {
- mEditChip.setVisibility(View.VISIBLE);
- mActionContainerBackground.setVisibility(View.VISIBLE);
- mEditChip.setOnClickListener(listener);
- mEditChip.setContentDescription(
- mContext.getString(R.string.clipboard_edit_image_description));
- }
- return isEditableImage;
- }
-
- private void setAccessibilityActionToEdit(View view) {
- ViewCompat.replaceAccessibilityAction(view,
- AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK,
- mContext.getString(R.string.clipboard_edit), null);
- }
-
- private void animateIn() {
- if (mAccessibilityManager.isEnabled()) {
- mDismissButton.setVisibility(View.VISIBLE);
- }
- mEnterAnimator = getEnterAnimation();
- mEnterAnimator.start();
- }
-
- private void animateOut() {
- if (mExitAnimator != null && mExitAnimator.isRunning()) {
- return;
- }
- Animator anim = getExitAnimation();
- anim.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- super.onAnimationCancel(animation);
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- if (!mCancelled) {
- hideImmediate();
- }
- }
- });
- mExitAnimator = anim;
- anim.start();
- }
-
- private Animator getEnterAnimation() {
- TimeInterpolator linearInterpolator = new LinearInterpolator();
- TimeInterpolator scaleInterpolator = new PathInterpolator(0, 0, 0, 1f);
- AnimatorSet enterAnim = new AnimatorSet();
-
- ValueAnimator rootAnim = ValueAnimator.ofFloat(0, 1);
- rootAnim.setInterpolator(linearInterpolator);
- rootAnim.setDuration(66);
- rootAnim.addUpdateListener(animation -> {
- mView.setAlpha(animation.getAnimatedFraction());
- });
-
- ValueAnimator scaleAnim = ValueAnimator.ofFloat(0, 1);
- scaleAnim.setInterpolator(scaleInterpolator);
- scaleAnim.setDuration(333);
- scaleAnim.addUpdateListener(animation -> {
- float previewScale = MathUtils.lerp(.9f, 1f, animation.getAnimatedFraction());
- mClipboardPreview.setScaleX(previewScale);
- mClipboardPreview.setScaleY(previewScale);
- mPreviewBorder.setScaleX(previewScale);
- mPreviewBorder.setScaleY(previewScale);
-
- float pivotX = mClipboardPreview.getWidth() / 2f + mClipboardPreview.getX();
- mActionContainerBackground.setPivotX(pivotX - mActionContainerBackground.getX());
- mActionContainer.setPivotX(pivotX - ((View) mActionContainer.getParent()).getX());
- float actionsScaleX = MathUtils.lerp(.7f, 1f, animation.getAnimatedFraction());
- float actionsScaleY = MathUtils.lerp(.9f, 1f, animation.getAnimatedFraction());
- mActionContainer.setScaleX(actionsScaleX);
- mActionContainer.setScaleY(actionsScaleY);
- mActionContainerBackground.setScaleX(actionsScaleX);
- mActionContainerBackground.setScaleY(actionsScaleY);
- });
-
- ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
- alphaAnim.setInterpolator(linearInterpolator);
- alphaAnim.setDuration(283);
- alphaAnim.addUpdateListener(animation -> {
- float alpha = animation.getAnimatedFraction();
- mClipboardPreview.setAlpha(alpha);
- mPreviewBorder.setAlpha(alpha);
- mDismissButton.setAlpha(alpha);
- mActionContainer.setAlpha(alpha);
- });
-
- mActionContainer.setAlpha(0);
- mPreviewBorder.setAlpha(0);
- mClipboardPreview.setAlpha(0);
- enterAnim.play(rootAnim).with(scaleAnim);
- enterAnim.play(alphaAnim).after(50).after(rootAnim);
-
- enterAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mView.setAlpha(1);
- mTimeoutHandler.resetTimeout();
- }
- });
- return enterAnim;
- }
-
- private Animator getExitAnimation() {
- TimeInterpolator linearInterpolator = new LinearInterpolator();
- TimeInterpolator scaleInterpolator = new PathInterpolator(.3f, 0, 1f, 1f);
- AnimatorSet exitAnim = new AnimatorSet();
-
- ValueAnimator rootAnim = ValueAnimator.ofFloat(0, 1);
- rootAnim.setInterpolator(linearInterpolator);
- rootAnim.setDuration(100);
- rootAnim.addUpdateListener(anim -> mView.setAlpha(1 - anim.getAnimatedFraction()));
-
- ValueAnimator scaleAnim = ValueAnimator.ofFloat(0, 1);
- scaleAnim.setInterpolator(scaleInterpolator);
- scaleAnim.setDuration(250);
- scaleAnim.addUpdateListener(animation -> {
- float previewScale = MathUtils.lerp(1f, .9f, animation.getAnimatedFraction());
- mClipboardPreview.setScaleX(previewScale);
- mClipboardPreview.setScaleY(previewScale);
- mPreviewBorder.setScaleX(previewScale);
- mPreviewBorder.setScaleY(previewScale);
-
- float pivotX = mClipboardPreview.getWidth() / 2f + mClipboardPreview.getX();
- mActionContainerBackground.setPivotX(pivotX - mActionContainerBackground.getX());
- mActionContainer.setPivotX(pivotX - ((View) mActionContainer.getParent()).getX());
- float actionScaleX = MathUtils.lerp(1f, .8f, animation.getAnimatedFraction());
- float actionScaleY = MathUtils.lerp(1f, .9f, animation.getAnimatedFraction());
- mActionContainer.setScaleX(actionScaleX);
- mActionContainer.setScaleY(actionScaleY);
- mActionContainerBackground.setScaleX(actionScaleX);
- mActionContainerBackground.setScaleY(actionScaleY);
- });
-
- ValueAnimator alphaAnim = ValueAnimator.ofFloat(0, 1);
- alphaAnim.setInterpolator(linearInterpolator);
- alphaAnim.setDuration(166);
- alphaAnim.addUpdateListener(animation -> {
- float alpha = 1 - animation.getAnimatedFraction();
- mClipboardPreview.setAlpha(alpha);
- mPreviewBorder.setAlpha(alpha);
- mDismissButton.setAlpha(alpha);
- mActionContainer.setAlpha(alpha);
- });
-
- exitAnim.play(alphaAnim).with(scaleAnim);
- exitAnim.play(rootAnim).after(150).after(alphaAnim);
- return exitAnim;
- }
-
- private void hideImmediate() {
- // Note this may be called multiple times if multiple dismissal events happen at the same
- // time.
- mTimeoutHandler.cancelTimeout();
- final View decorView = mWindow.peekDecorView();
- if (decorView != null && decorView.isAttachedToWindow()) {
- mWindowManager.removeViewImmediate(decorView);
- }
- if (mCloseDialogsReceiver != null) {
- mBroadcastDispatcher.unregisterReceiver(mCloseDialogsReceiver);
- mCloseDialogsReceiver = null;
- }
- if (mScreenshotReceiver != null) {
- mBroadcastDispatcher.unregisterReceiver(mScreenshotReceiver);
- mScreenshotReceiver = null;
- }
- if (mInputEventReceiver != null) {
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- }
- if (mInputMonitor != null) {
- mInputMonitor.dispose();
- mInputMonitor = null;
- }
- if (mOnSessionCompleteListener != null) {
- mOnSessionCompleteListener.run();
- }
- }
-
- private void resetActionChips() {
- for (OverlayActionChip chip : mActionChips) {
- mActionContainer.removeView(chip);
- }
- mActionChips.clear();
- }
-
- private void reset() {
- mView.setTranslationX(0);
- mView.setAlpha(0);
- mActionContainerBackground.setVisibility(View.GONE);
- mShareChip.setVisibility(View.GONE);
- mEditChip.setVisibility(View.GONE);
- mRemoteCopyChip.setVisibility(View.GONE);
- resetActionChips();
- mTimeoutHandler.cancelTimeout();
- mClipboardLogger.reset();
- }
-
- @MainThread
- private void attachWindow() {
- View decorView = mWindow.getDecorView();
- if (decorView.isAttachedToWindow() || mBlockAttach) {
- return;
- }
- mBlockAttach = true;
- mWindowManager.addView(decorView, mWindowLayoutParams);
- decorView.requestApplyInsets();
- mView.requestApplyInsets();
- decorView.getViewTreeObserver().addOnWindowAttachListener(
- new ViewTreeObserver.OnWindowAttachListener() {
- @Override
- public void onWindowAttached() {
- mBlockAttach = false;
- }
-
- @Override
- public void onWindowDetached() {
- }
- }
- );
- }
-
- private void withWindowAttached(Runnable action) {
- View decorView = mWindow.getDecorView();
- if (decorView.isAttachedToWindow()) {
- action.run();
- } else {
- decorView.getViewTreeObserver().addOnWindowAttachListener(
- new ViewTreeObserver.OnWindowAttachListener() {
- @Override
- public void onWindowAttached() {
- mBlockAttach = false;
- decorView.getViewTreeObserver().removeOnWindowAttachListener(this);
- action.run();
- }
-
- @Override
- public void onWindowDetached() {
- }
- });
- }
- }
-
- private void updateInsets(WindowInsets insets) {
- int orientation = mContext.getResources().getConfiguration().orientation;
- FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) mView.getLayoutParams();
- if (p == null) {
- return;
- }
- DisplayCutout cutout = insets.getDisplayCutout();
- Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
- Insets imeInsets = insets.getInsets(WindowInsets.Type.ime());
- if (cutout == null) {
- p.setMargins(0, 0, 0, Math.max(imeInsets.bottom, navBarInsets.bottom));
- } else {
- Insets waterfall = cutout.getWaterfallInsets();
- if (orientation == ORIENTATION_PORTRAIT) {
- p.setMargins(
- waterfall.left,
- Math.max(cutout.getSafeInsetTop(), waterfall.top),
- waterfall.right,
- Math.max(imeInsets.bottom,
- Math.max(cutout.getSafeInsetBottom(),
- Math.max(navBarInsets.bottom, waterfall.bottom))));
- } else {
- p.setMargins(
- waterfall.left,
- waterfall.top,
- waterfall.right,
- Math.max(imeInsets.bottom,
- Math.max(navBarInsets.bottom, waterfall.bottom)));
- }
- }
- mView.setLayoutParams(p);
- mView.requestLayout();
- }
-
- private Display getDefaultDisplay() {
- return mDisplayManager.getDisplay(DEFAULT_DISPLAY);
- }
-
- /**
- * Updates the window focusability. If the window is already showing, then it updates the
- * window immediately, otherwise the layout params will be applied when the window is next
- * shown.
- */
- private void setWindowFocusable(boolean focusable) {
- int flags = mWindowLayoutParams.flags;
- if (focusable) {
- mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- } else {
- mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- }
- if (mWindowLayoutParams.flags == flags) {
- return;
- }
- final View decorView = mWindow.peekDecorView();
- if (decorView != null && decorView.isAttachedToWindow()) {
- mWindowManager.updateViewLayout(decorView, mWindowLayoutParams);
- }
- }
-
- static class ClipboardLogger {
- private final UiEventLogger mUiEventLogger;
- private boolean mGuarded = false;
-
- ClipboardLogger(UiEventLogger uiEventLogger) {
- mUiEventLogger = uiEventLogger;
- }
-
- void logSessionComplete(@NonNull UiEventLogger.UiEventEnum event) {
- if (!mGuarded) {
- mGuarded = true;
- mUiEventLogger.log(event);
- }
- }
-
- void reset() {
- mGuarded = false;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java
deleted file mode 100644
index 0d989a7..0000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerLegacyFactory.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.clipboardoverlay;
-
-import android.content.Context;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.screenshot.TimeoutHandler;
-
-import javax.inject.Inject;
-
-/**
- * A factory that churns out ClipboardOverlayControllerLegacys on demand.
- */
-@SysUISingleton
-public class ClipboardOverlayControllerLegacyFactory {
-
- private final UiEventLogger mUiEventLogger;
- private final BroadcastDispatcher mBroadcastDispatcher;
- private final BroadcastSender mBroadcastSender;
-
- @Inject
- public ClipboardOverlayControllerLegacyFactory(BroadcastDispatcher broadcastDispatcher,
- BroadcastSender broadcastSender, UiEventLogger uiEventLogger) {
- this.mBroadcastDispatcher = broadcastDispatcher;
- this.mBroadcastSender = broadcastSender;
- this.mUiEventLogger = uiEventLogger;
- }
-
- /**
- * One new ClipboardOverlayControllerLegacy, coming right up!
- */
- public ClipboardOverlayControllerLegacy create(Context context) {
- return new ClipboardOverlayControllerLegacy(context, mBroadcastDispatcher, mBroadcastSender,
- new TimeoutHandler(context), mUiEventLogger);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
index 2244813..09b2e44 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
@@ -16,7 +16,6 @@
package com.android.systemui.clipboardoverlay.dagger;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -28,6 +27,7 @@
import com.android.systemui.R;
import com.android.systemui.clipboardoverlay.ClipboardOverlayView;
+import com.android.systemui.settings.DisplayTracker;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -46,8 +46,9 @@
*/
@Provides
@OverlayWindowContext
- static Context provideWindowContext(DisplayManager displayManager, Context context) {
- Display display = displayManager.getDisplay(DEFAULT_DISPLAY);
+ static Context provideWindowContext(DisplayManager displayManager,
+ DisplayTracker displayTracker, Context context) {
+ Display display = displayManager.getDisplay(displayTracker.getDefaultDisplayId());
return context.createWindowContext(display, TYPE_SCREENSHOT, null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableConstraintLayout.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableConstraintLayout.kt
new file mode 100644
index 0000000..9763665
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableConstraintLayout.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.common.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.constraintlayout.widget.ConstraintLayout
+import com.android.systemui.animation.LaunchableView
+import com.android.systemui.animation.LaunchableViewDelegate
+
+/** A [ConstraintLayout] that also implements [LaunchableView]. */
+open class LaunchableConstraintLayout : ConstraintLayout, LaunchableView {
+ private val delegate =
+ LaunchableViewDelegate(
+ this,
+ superSetVisibility = { super.setVisibility(it) },
+ )
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ defStyleRes: Int
+ ) : super(context, attrs, defStyleAttr, defStyleRes)
+
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {
+ delegate.setShouldBlockVisibilityChanges(block)
+ }
+
+ override fun setVisibility(visibility: Int) {
+ delegate.setVisibility(visibility)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt
index ddde628..2edac52 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableLinearLayout.kt
@@ -23,7 +23,7 @@
import com.android.systemui.animation.LaunchableViewDelegate
/** A [LinearLayout] that also implements [LaunchableView]. */
-class LaunchableLinearLayout : LinearLayout, LaunchableView {
+open class LaunchableLinearLayout : LinearLayout, LaunchableView {
private val delegate =
LaunchableViewDelegate(
this,
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
new file mode 100644
index 0000000..2dd98dc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingView.kt
@@ -0,0 +1,123 @@
+/*
+ * 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.common.ui.view
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import kotlin.math.pow
+import kotlin.math.sqrt
+import kotlinx.coroutines.DisposableHandle
+
+/**
+ * View designed to handle long-presses.
+ *
+ * The view will not handle any long pressed by default. To set it up, set up a listener and, when
+ * ready to start consuming long-presses, set [setLongPressHandlingEnabled] to `true`.
+ */
+class LongPressHandlingView(
+ context: Context,
+ attrs: AttributeSet?,
+) :
+ View(
+ context,
+ attrs,
+ ) {
+ interface Listener {
+ /** Notifies that a long-press has been detected by the given view. */
+ fun onLongPressDetected(
+ view: View,
+ x: Int,
+ y: Int,
+ )
+
+ /** Notifies that the gesture was too short for a long press, it is actually a click. */
+ fun onSingleTapDetected(view: View) = Unit
+ }
+
+ var listener: Listener? = null
+
+ private val interactionHandler: LongPressHandlingViewInteractionHandler by lazy {
+ LongPressHandlingViewInteractionHandler(
+ postDelayed = { block, timeoutMs ->
+ val dispatchToken = Any()
+
+ handler.postDelayed(
+ block,
+ dispatchToken,
+ timeoutMs,
+ )
+
+ DisposableHandle { handler.removeCallbacksAndMessages(dispatchToken) }
+ },
+ isAttachedToWindow = ::isAttachedToWindow,
+ onLongPressDetected = { x, y ->
+ listener?.onLongPressDetected(
+ view = this,
+ x = x,
+ y = y,
+ )
+ },
+ onSingleTapDetected = { listener?.onSingleTapDetected(this@LongPressHandlingView) },
+ )
+ }
+
+ fun setLongPressHandlingEnabled(isEnabled: Boolean) {
+ interactionHandler.isLongPressHandlingEnabled = isEnabled
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onTouchEvent(event: MotionEvent?): Boolean {
+ return interactionHandler.onTouchEvent(event?.toModel())
+ }
+}
+
+private fun MotionEvent.toModel(): LongPressHandlingViewInteractionHandler.MotionEventModel {
+ return when (actionMasked) {
+ MotionEvent.ACTION_DOWN ->
+ LongPressHandlingViewInteractionHandler.MotionEventModel.Down(
+ x = x.toInt(),
+ y = y.toInt(),
+ )
+ MotionEvent.ACTION_MOVE ->
+ LongPressHandlingViewInteractionHandler.MotionEventModel.Move(
+ distanceMoved = distanceMoved(),
+ )
+ MotionEvent.ACTION_UP ->
+ LongPressHandlingViewInteractionHandler.MotionEventModel.Up(
+ distanceMoved = distanceMoved(),
+ gestureDuration = gestureDuration(),
+ )
+ MotionEvent.ACTION_CANCEL -> LongPressHandlingViewInteractionHandler.MotionEventModel.Cancel
+ else -> LongPressHandlingViewInteractionHandler.MotionEventModel.Other
+ }
+}
+
+private fun MotionEvent.distanceMoved(): Float {
+ return if (historySize > 0) {
+ sqrt((x - getHistoricalX(0)).pow(2) + (y - getHistoricalY(0)).pow(2))
+ } else {
+ 0f
+ }
+}
+
+private fun MotionEvent.gestureDuration(): Long {
+ return eventTime - downTime
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
new file mode 100644
index 0000000..c2d4d12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandler.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.common.ui.view
+
+import android.view.ViewConfiguration
+import kotlinx.coroutines.DisposableHandle
+
+/** Encapsulates logic to handle complex touch interactions with a [LongPressHandlingView]. */
+class LongPressHandlingViewInteractionHandler(
+ /**
+ * Callback to run the given [Runnable] with the given delay, returning a [DisposableHandle]
+ * allowing the delayed runnable to be canceled before it is run.
+ */
+ private val postDelayed: (block: Runnable, delayMs: Long) -> DisposableHandle,
+ /** Callback to be queried to check if the view is attached to its window. */
+ private val isAttachedToWindow: () -> Boolean,
+ /** Callback reporting the a long-press gesture was detected at the given coordinates. */
+ private val onLongPressDetected: (x: Int, y: Int) -> Unit,
+ /** Callback reporting the a single tap gesture was detected at the given coordinates. */
+ private val onSingleTapDetected: () -> Unit,
+) {
+ sealed class MotionEventModel {
+ object Other : MotionEventModel()
+
+ data class Down(
+ val x: Int,
+ val y: Int,
+ ) : MotionEventModel()
+
+ data class Move(
+ val distanceMoved: Float,
+ ) : MotionEventModel()
+
+ data class Up(
+ val distanceMoved: Float,
+ val gestureDuration: Long,
+ ) : MotionEventModel()
+
+ object Cancel : MotionEventModel()
+ }
+
+ var isLongPressHandlingEnabled: Boolean = false
+ var scheduledLongPressHandle: DisposableHandle? = null
+
+ fun onTouchEvent(event: MotionEventModel?): Boolean {
+ if (!isLongPressHandlingEnabled) {
+ return false
+ }
+
+ return when (event) {
+ is MotionEventModel.Down -> {
+ scheduleLongPress(event.x, event.y)
+ true
+ }
+ is MotionEventModel.Move -> {
+ if (event.distanceMoved > ViewConfiguration.getTouchSlop()) {
+ cancelScheduledLongPress()
+ }
+ false
+ }
+ is MotionEventModel.Up -> {
+ cancelScheduledLongPress()
+ if (
+ event.distanceMoved <= ViewConfiguration.getTouchSlop() &&
+ event.gestureDuration < ViewConfiguration.getLongPressTimeout()
+ ) {
+ dispatchSingleTap()
+ }
+ false
+ }
+ is MotionEventModel.Cancel -> {
+ cancelScheduledLongPress()
+ false
+ }
+ else -> false
+ }
+ }
+
+ private fun scheduleLongPress(
+ x: Int,
+ y: Int,
+ ) {
+ scheduledLongPressHandle =
+ postDelayed(
+ {
+ dispatchLongPress(
+ x = x,
+ y = y,
+ )
+ },
+ ViewConfiguration.getLongPressTimeout().toLong(),
+ )
+ }
+
+ private fun dispatchLongPress(
+ x: Int,
+ y: Int,
+ ) {
+ if (!isAttachedToWindow()) {
+ return
+ }
+
+ onLongPressDetected(x, y)
+ }
+
+ private fun cancelScheduledLongPress() {
+ scheduledLongPressHandle?.dispose()
+ }
+
+ private fun dispatchSingleTap() {
+ if (!isAttachedToWindow()) {
+ return
+ }
+
+ onSingleTapDetected()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 54587b2..3808e73 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -189,9 +189,9 @@
authorizedPanelsRepository.addAuthorizedPanels(
setOf(serviceInfo.componentName.packageName)
)
- animateExitAndFinish()
val selected = SelectedItem.PanelItem(appName, componentName)
controlsController.setPreferredSelection(selected)
+ animateExitAndFinish()
openControlsOrigin()
}
dialog = null
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 966dbf1..9e71bef 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -25,6 +25,7 @@
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
@@ -38,6 +39,7 @@
import android.view.animation.DecelerateInterpolator
import android.widget.AdapterView
import android.widget.ArrayAdapter
+import android.widget.BaseAdapter
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
@@ -90,6 +92,7 @@
class ControlsUiControllerImpl @Inject constructor (
val controlsController: Lazy<ControlsController>,
val context: Context,
+ private val packageManager: PackageManager,
@Main val uiExecutor: DelayableExecutor,
@Background val bgExecutor: DelayableExecutor,
val controlsListingController: Lazy<ControlsListingController>,
@@ -113,6 +116,11 @@
private const val PREF_IS_PANEL = "controls_is_panel"
private const val FADE_IN_MILLIS = 200L
+
+ private const val OPEN_APP_ID = 0L
+ private const val ADD_CONTROLS_ID = 1L
+ private const val ADD_APP_ID = 2L
+ private const val EDIT_CONTROLS_ID = 3L
}
private var selectedItem: SelectedItem = SelectedItem.EMPTY_SELECTION
@@ -140,6 +148,9 @@
it.getTitle()
}
+ private var openAppIntent: Intent? = null
+ private var overflowMenuAdapter: BaseAdapter? = null
+
private val onSeedingComplete = Consumer<Boolean> {
accepted ->
if (accepted) {
@@ -216,6 +227,8 @@
this.parent = parent
this.onDismiss = onDismiss
this.activityContext = activityContext
+ this.openAppIntent = null
+ this.overflowMenuAdapter = null
hidden = false
retainCache = false
@@ -306,6 +319,12 @@
startTargetedActivity(si, ControlsEditingActivity::class.java)
}
+ private fun startDefaultActivity() {
+ openAppIntent?.let {
+ startActivity(it, animateExtra = false)
+ }
+ }
+
private fun startTargetedActivity(si: StructureInfo, klazz: Class<*>) {
val i = Intent(activityContext, klazz)
putIntentExtras(i, si)
@@ -329,9 +348,11 @@
startActivity(i)
}
- private fun startActivity(intent: Intent) {
+ private fun startActivity(intent: Intent, animateExtra: Boolean = true) {
// Force animations when transitioning from a dialog to an activity
- intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+ if (animateExtra) {
+ intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+ }
if (keyguardStateController.isShowing()) {
activityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */)
@@ -383,8 +404,31 @@
Log.w(ControlsUiController.TAG, "Not TaskViewFactory to display panel $selectionItem")
}
+ bgExecutor.execute {
+ val intent = Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(selectionItem.componentName.packageName)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+ val intents = packageManager
+ .queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0L))
+ intents.firstOrNull { it.activityInfo.exported }?.let { resolved ->
+ intent.setPackage(null)
+ intent.setComponent(resolved.activityInfo.componentName)
+ openAppIntent = intent
+ parent.post {
+ // This will call show on the PopupWindow in the same thread, so make sure this
+ // happens in the view thread.
+ overflowMenuAdapter?.notifyDataSetChanged()
+ }
+ }
+ }
createDropDown(panelsAndStructures, selectionItem)
- createMenu()
+
+ val currentApps = panelsAndStructures.map { it.componentName }.toSet()
+ val allApps = controlsListingController.get()
+ .getCurrentServices().map { it.componentName }.toSet()
+ createMenu(extraApps = (allApps - currentApps).isNotEmpty())
}
private fun createPanelView(componentName: ComponentName) {
@@ -423,28 +467,41 @@
}
}
- private fun createMenu() {
+ private fun createMenu(extraApps: Boolean) {
val isPanel = selectedItem is SelectedItem.PanelItem
val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
?: EMPTY_STRUCTURE
val newFlows = featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
- val addControlsId = if (newFlows || isPanel) {
- R.string.controls_menu_add_another_app
- } else {
- R.string.controls_menu_add
+
+ val items = buildList {
+ add(OverflowMenuAdapter.MenuItem(
+ context.getText(R.string.controls_open_app),
+ OPEN_APP_ID
+ ))
+ if (newFlows || isPanel) {
+ if (extraApps) {
+ add(OverflowMenuAdapter.MenuItem(
+ context.getText(R.string.controls_menu_add_another_app),
+ ADD_APP_ID
+ ))
+ }
+ } else {
+ add(OverflowMenuAdapter.MenuItem(
+ context.getText(R.string.controls_menu_add),
+ ADD_CONTROLS_ID
+ ))
+ }
+ if (!isPanel) {
+ add(OverflowMenuAdapter.MenuItem(
+ context.getText(R.string.controls_menu_edit),
+ EDIT_CONTROLS_ID
+ ))
+ }
}
- val items = if (isPanel) {
- arrayOf(
- context.resources.getString(addControlsId),
- )
- } else {
- arrayOf(
- context.resources.getString(addControlsId),
- context.resources.getString(R.string.controls_menu_edit)
- )
+ val adapter = OverflowMenuAdapter(context, R.layout.controls_more_item, items) { position ->
+ getItemId(position) != OPEN_APP_ID || openAppIntent != null
}
- var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items)
val anchor = parent.requireViewById<ImageView>(R.id.controls_more)
anchor.setOnClickListener(object : View.OnClickListener {
@@ -462,25 +519,21 @@
pos: Int,
id: Long
) {
- when (pos) {
- // 0: Add Control
- 0 -> {
- if (isPanel || newFlows) {
- startProviderSelectorActivity()
- } else {
- startFavoritingActivity(selectedStructure)
- }
- }
- // 1: Edit controls
- 1 -> startEditingActivity(selectedStructure)
+ when (id) {
+ OPEN_APP_ID -> startDefaultActivity()
+ ADD_APP_ID -> startProviderSelectorActivity()
+ ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure)
+ EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure)
}
dismiss()
}
})
show()
+ listView?.post { listView?.requestAccessibilityFocus() }
}
}
})
+ overflowMenuAdapter = adapter
}
private fun createDropDown(items: List<SelectionItem>, selected: SelectionItem) {
@@ -542,6 +595,7 @@
}
})
show()
+ listView?.post { listView?.requestAccessibilityFocus() }
}
}
})
@@ -631,7 +685,7 @@
.putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
.putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
.putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
- .commit()
+ .apply()
}
private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt
new file mode 100644
index 0000000..6b84e36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/OverflowMenuAdapter.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.Context
+import android.widget.ArrayAdapter
+import androidx.annotation.LayoutRes
+
+open class OverflowMenuAdapter(
+ context: Context,
+ @LayoutRes layoutId: Int,
+ itemsWithIds: List<MenuItem>,
+ private val isEnabledInternal: OverflowMenuAdapter.(Int) -> Boolean
+) : ArrayAdapter<CharSequence>(context, layoutId, itemsWithIds.map(MenuItem::text)) {
+
+ private val ids = itemsWithIds.map(MenuItem::id)
+
+ override fun getItemId(position: Int): Long {
+ return ids[position]
+ }
+
+ override fun isEnabled(position: Int): Boolean {
+ return isEnabledInternal(position)
+ }
+
+ data class MenuItem(val text: CharSequence, val id: Long)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 8e9992f..ef07e99 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -27,6 +27,7 @@
import com.android.systemui.biometrics.AuthController
import com.android.systemui.clipboardoverlay.ClipboardListener
import com.android.systemui.dagger.qualifiers.PerUser
+import com.android.systemui.dreams.DreamMonitor
import com.android.systemui.globalactions.GlobalActionsComponent
import com.android.systemui.keyboard.KeyboardUI
import com.android.systemui.keyguard.KeyguardViewMediator
@@ -286,4 +287,10 @@
@IntoMap
@ClassKey(StylusUsiPowerStartable::class)
abstract fun bindStylusUsiPowerStartable(sysui: StylusUsiPowerStartable): CoreStartable
+
+ /**Inject into DreamMonitor */
+ @Binds
+ @IntoMap
+ @ClassKey(DreamMonitor::class)
+ abstract fun bindDreamMonitor(sysui: DreamMonitor): CoreStartable
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 2d0dfa1..9ad7b8c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -63,6 +63,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.security.data.repository.SecurityRepositoryModule;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.dagger.MultiUserUtilsModule;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.smartspace.dagger.SmartspaceModule;
@@ -107,6 +108,8 @@
import java.util.Optional;
import java.util.concurrent.Executor;
+import javax.inject.Named;
+
import dagger.Binds;
import dagger.BindsOptionalOf;
import dagger.Module;
@@ -196,8 +199,8 @@
@SysUISingleton
@Provides
- static SysUiState provideSysUiState(DumpManager dumpManager) {
- final SysUiState state = new SysUiState();
+ static SysUiState provideSysUiState(DisplayTracker displayTracker, DumpManager dumpManager) {
+ final SysUiState state = new SysUiState(displayTracker);
dumpManager.registerDumpable(state);
return state;
}
@@ -215,6 +218,10 @@
abstract BcSmartspaceConfigPlugin optionalBcSmartspaceConfigPlugin();
@BindsOptionalOf
+ @Named(SmartspaceModule.WEATHER_SMARTSPACE_DATA_PLUGIN)
+ abstract BcSmartspaceDataPlugin optionalWeatherSmartspaceConfigPlugin();
+
+ @BindsOptionalOf
abstract Recents optionalRecents();
@BindsOptionalOf
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
new file mode 100644
index 0000000..102f208
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams;
+
+import android.util.Log;
+
+import com.android.systemui.CoreStartable;
+import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback;
+import com.android.systemui.dreams.conditions.DreamCondition;
+import com.android.systemui.shared.condition.Monitor;
+
+import javax.inject.Inject;
+
+/**
+ * A {@link CoreStartable} to retain a monitor for tracking dreaming.
+ */
+public class DreamMonitor implements CoreStartable {
+ private static final String TAG = "DreamMonitor";
+
+ // We retain a reference to the monitor so it is not garbage-collected.
+ private final Monitor mConditionMonitor;
+ private final DreamCondition mDreamCondition;
+ private final DreamStatusBarStateCallback mCallback;
+
+
+ @Inject
+ public DreamMonitor(Monitor monitor, DreamCondition dreamCondition,
+ DreamStatusBarStateCallback callback) {
+ mConditionMonitor = monitor;
+ mDreamCondition = dreamCondition;
+ mCallback = callback;
+
+ }
+ @Override
+ public void start() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "started");
+ }
+
+ mConditionMonitor.addSubscription(new Monitor.Subscription.Builder(mCallback)
+ .addCondition(mDreamCondition)
+ .build());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index c882f8a..c3bd5d9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -182,6 +182,18 @@
}
}
+ /**
+ * Ends the dream content and dream overlay animations, if they're currently running.
+ * @see [AnimatorSet.end]
+ */
+ fun endAnimations() {
+ mAnimator =
+ mAnimator?.let {
+ it.end()
+ null
+ }
+ }
+
private fun blurAnimator(
view: View,
fromBlurRadius: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 33c8379..50cfb6a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -37,11 +37,11 @@
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
+import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.BlurUtils;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -56,7 +56,6 @@
@DreamOverlayComponent.DreamOverlayScope
public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
private final DreamOverlayStatusBarViewController mStatusBarViewController;
- private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final BlurUtils mBlurUtils;
private final DreamOverlayAnimationsController mDreamOverlayAnimationsController;
private final DreamOverlayStateController mStateController;
@@ -85,6 +84,22 @@
private long mJitterStartTimeMillis;
private boolean mBouncerAnimating;
+ private boolean mWakingUpFromSwipe;
+
+ private final BouncerlessScrimController mBouncerlessScrimController;
+
+ private final BouncerlessScrimController.Callback mBouncerlessExpansionCallback =
+ new BouncerlessScrimController.Callback() {
+ @Override
+ public void onExpansion(ShadeExpansionChangeEvent event) {
+ updateTransitionState(event.getFraction());
+ }
+
+ @Override
+ public void onWakeup() {
+ mWakingUpFromSwipe = true;
+ }
+ };
private final PrimaryBouncerExpansionCallback
mBouncerExpansionCallback =
@@ -127,13 +142,29 @@
}
};
+ /**
+ * If true, overlay entry animations should be skipped once.
+ *
+ * This is turned on when exiting low light and should be turned off once the entry animations
+ * are skipped once.
+ */
+ private boolean mSkipEntryAnimations;
+
+ private final DreamOverlayStateController.Callback
+ mDreamOverlayStateCallback =
+ new DreamOverlayStateController.Callback() {
+ @Override
+ public void onExitLowLight() {
+ mSkipEntryAnimations = true;
+ }
+ };
+
@Inject
public DreamOverlayContainerViewController(
DreamOverlayContainerView containerView,
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
DreamOverlayStatusBarViewController statusBarViewController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager,
BlurUtils blurUtils,
@Main Handler handler,
@Main Resources resources,
@@ -143,15 +174,18 @@
@Named(DreamOverlayModule.MILLIS_UNTIL_FULL_JITTER) long millisUntilFullJitter,
PrimaryBouncerCallbackInteractor primaryBouncerCallbackInteractor,
DreamOverlayAnimationsController animationsController,
- DreamOverlayStateController stateController) {
+ DreamOverlayStateController stateController,
+ BouncerlessScrimController bouncerlessScrimController) {
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
- mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mBlurUtils = blurUtils;
mDreamOverlayAnimationsController = animationsController;
mStateController = stateController;
+ mBouncerlessScrimController = bouncerlessScrimController;
+ mBouncerlessScrimController.addCallback(mBouncerlessExpansionCallback);
+
mComplicationHostViewController = complicationHostViewController;
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
R.dimen.dream_overlay_y_offset);
@@ -170,6 +204,7 @@
@Override
protected void onInit() {
+ mStateController.addCallback(mDreamOverlayStateCallback);
mStatusBarViewController.init();
mComplicationHostViewController.init();
mDreamOverlayAnimationsController.init(mView);
@@ -177,27 +212,27 @@
@Override
protected void onViewAttached() {
+ mWakingUpFromSwipe = false;
mJitterStartTimeMillis = System.currentTimeMillis();
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
- final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getPrimaryBouncer();
- if (bouncer != null) {
- bouncer.addBouncerExpansionCallback(mBouncerExpansionCallback);
- }
mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mBouncerExpansionCallback);
// Start dream entry animations. Skip animations for low light clock.
if (!mStateController.isLowLightActive()) {
mDreamOverlayAnimationsController.startEntryAnimations();
+
+ if (mSkipEntryAnimations) {
+ // If we're transitioning from the low light dream back to the user dream, skip the
+ // overlay animations and show immediately.
+ mDreamOverlayAnimationsController.endAnimations();
+ mSkipEntryAnimations = false;
+ }
}
}
@Override
protected void onViewDetached() {
mHandler.removeCallbacks(this::updateBurnInOffsets);
- final KeyguardBouncer bouncer = mStatusBarKeyguardViewManager.getPrimaryBouncer();
- if (bouncer != null) {
- bouncer.removeBouncerExpansionCallback(mBouncerExpansionCallback);
- }
mPrimaryBouncerCallbackInteractor.removeBouncerExpansionCallback(mBouncerExpansionCallback);
mDreamOverlayAnimationsController.cancelAnimations();
@@ -266,6 +301,13 @@
*/
public void wakeUp(@NonNull Runnable onAnimationEnd,
@NonNull DelayableExecutor callbackExecutor) {
+ // When swiping causes wakeup, do not run any animations as the dream should exit as soon
+ // as possible.
+ if (mWakingUpFromSwipe) {
+ onAnimationEnd.run();
+ return;
+ }
+
mDreamOverlayAnimationsController.wakeUp(onAnimationEnd, callbackExecutor);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index ccfdd096..2c7ecb1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -83,6 +83,12 @@
*/
default void onAvailableComplicationTypesChanged() {
}
+
+ /**
+ * Called when the low light dream is exiting and transitioning back to the user dream.
+ */
+ default void onExitLowLight() {
+ }
}
private final Executor mExecutor;
@@ -278,6 +284,10 @@
* @param active {@code true} if low light mode is active, {@code false} otherwise.
*/
public void setLowLightActive(boolean active) {
+ if (isLowLightActive() && !active) {
+ // Notify that we're exiting low light only on the transition from active to not active.
+ mCallbacks.forEach(Callback::onExitLowLight);
+ }
modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_LOW_LIGHT_ACTIVE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java
new file mode 100644
index 0000000..c8c9470
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/callbacks/DreamStatusBarStateCallback.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.dreams.callbacks;
+
+import android.util.Log;
+
+import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+
+import javax.inject.Inject;
+
+/**
+ * A callback that informs {@link SysuiStatusBarStateController} when the dream state has changed.
+ */
+public class DreamStatusBarStateCallback implements Monitor.Callback {
+ private static final String TAG = "DreamStatusBarCallback";
+
+ private final SysuiStatusBarStateController mStateController;
+
+ @Inject
+ public DreamStatusBarStateCallback(SysuiStatusBarStateController statusBarStateController) {
+ mStateController = statusBarStateController;
+ }
+
+ @Override
+ public void onConditionsChanged(boolean allConditionsMet) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "onConditionChanged:" + allConditionsMet);
+ }
+
+ mStateController.setIsDreaming(allConditionsMet);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
new file mode 100644
index 0000000..2befce7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.dreams.conditions;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.text.TextUtils;
+
+import com.android.systemui.shared.condition.Condition;
+
+import javax.inject.Inject;
+
+/**
+ * {@link DreamCondition} provides a signal when a dream begins and ends.
+ */
+public class DreamCondition extends Condition {
+ private final Context mContext;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ processIntent(intent);
+ }
+ };
+
+ @Inject
+ public DreamCondition(Context context) {
+ mContext = context;
+ }
+
+ private void processIntent(Intent intent) {
+ // In the case of a non-existent sticky broadcast, ignore when there is no intent.
+ if (intent == null) {
+ return;
+ }
+ if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STARTED)) {
+ updateCondition(true);
+ } else if (TextUtils.equals(intent.getAction(), Intent.ACTION_DREAMING_STOPPED)) {
+ updateCondition(false);
+ } else {
+ throw new IllegalStateException("unexpected intent:" + intent);
+ }
+ }
+
+ @Override
+ protected void start() {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_DREAMING_STARTED);
+ filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+ final Intent stickyIntent = mContext.registerReceiver(mReceiver, filter);
+ processIntent(stickyIntent);
+ }
+
+ @Override
+ protected void stop() {
+ mContext.unregisterReceiver(mReceiver);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index e7b29bb..0ab8c8e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -28,6 +28,7 @@
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
import com.android.systemui.dreams.DreamOverlayService;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
+import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule;
import java.util.Optional;
@@ -42,6 +43,7 @@
@Module(includes = {
RegisteredComplicationsModule.class,
LowLightDreamModule.class,
+ ScrimModule.class
},
subcomponents = {
DreamOverlayComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 44207f4..73c2289 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -36,11 +36,12 @@
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.dreams.touch.scrim.ScrimController;
+import com.android.systemui.dreams.touch.scrim.ScrimManager;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.util.Optional;
@@ -78,7 +79,8 @@
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final float mBouncerZoneScreenPercentage;
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final ScrimManager mScrimManager;
+ private ScrimController mCurrentScrimController;
private float mCurrentExpansion;
private final Optional<CentralSurfaces> mCentralSurfaces;
@@ -90,6 +92,7 @@
private final DisplayMetrics mDisplayMetrics;
private Boolean mCapture;
+ private Boolean mExpanded;
private boolean mBouncerInitiallyShowing;
@@ -101,6 +104,17 @@
private final UiEventLogger mUiEventLogger;
+ private final ScrimManager.Callback mScrimManagerCallback = new ScrimManager.Callback() {
+ @Override
+ public void onScrimControllerChanged(ScrimController controller) {
+ if (mCurrentScrimController != null) {
+ mCurrentScrimController.reset();
+ }
+
+ mCurrentScrimController = controller;
+ }
+ };
+
private final GestureDetector.OnGestureListener mOnGestureListener =
new GestureDetector.SimpleOnGestureListener() {
@Override
@@ -115,8 +129,10 @@
.orElse(false);
if (mCapture) {
+ // reset expanding
+ mExpanded = false;
// Since the user is dragging the bouncer up, set scrimmed to false.
- mStatusBarKeyguardViewManager.showPrimaryBouncer(false);
+ mCurrentScrimController.show();
}
}
@@ -157,10 +173,10 @@
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
/* fraction= */ mCurrentExpansion,
- /* expanded= */ false,
+ /* expanded= */ mExpanded,
/* tracking= */ true,
/* dragDownPxAmount= */ dragDownAmount);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(event);
+ mCurrentScrimController.expand(event);
}
@@ -187,7 +203,7 @@
@Inject
public BouncerSwipeTouchHandler(
DisplayMetrics displayMetrics,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ ScrimManager scrimManager,
Optional<CentralSurfaces> centralSurfaces,
NotificationShadeWindowController notificationShadeWindowController,
ValueAnimatorCreator valueAnimatorCreator,
@@ -200,7 +216,7 @@
UiEventLogger uiEventLogger) {
mDisplayMetrics = displayMetrics;
mCentralSurfaces = centralSurfaces;
- mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mScrimManager = scrimManager;
mNotificationShadeWindowController = notificationShadeWindowController;
mBouncerZoneScreenPercentage = swipeRegionPercentage;
mFlingAnimationUtils = flingAnimationUtils;
@@ -234,9 +250,12 @@
mTouchSession = session;
mVelocityTracker.clear();
mNotificationShadeWindowController.setForcePluginOpen(true, this);
+ mScrimManager.addCallback(mScrimManagerCallback);
+ mCurrentScrimController = mScrimManager.getCurrentController();
session.registerCallback(() -> {
mVelocityTracker.recycle();
+ mScrimManager.removeCallback(mScrimManagerCallback);
mCapture = null;
mNotificationShadeWindowController.setForcePluginOpen(false, this);
});
@@ -273,9 +292,10 @@
final float velocityVector =
(float) Math.hypot(horizontalVelocity, verticalVelocity);
- final float expansion = flingRevealsOverlay(verticalVelocity, velocityVector)
- ? KeyguardBouncerConstants.EXPANSION_HIDDEN
- : KeyguardBouncerConstants.EXPANSION_VISIBLE;
+ mExpanded = !flingRevealsOverlay(verticalVelocity, velocityVector);
+ final float expansion = mExpanded
+ ? KeyguardBouncerConstants.EXPANSION_VISIBLE
+ : KeyguardBouncerConstants.EXPANSION_HIDDEN;
// Log the swiping up to show Bouncer event.
if (!mBouncerInitiallyShowing
@@ -286,7 +306,7 @@
flingToExpansion(verticalVelocity, expansion);
if (expansion == KeyguardBouncerConstants.EXPANSION_HIDDEN) {
- mStatusBarKeyguardViewManager.reset(false);
+ mCurrentScrimController.reset();
}
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java
index 695b59a..b8b459e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitor.java
@@ -226,6 +226,15 @@
return;
}
+ // When we stop monitoring touches, we must ensure that all active touch sessions and
+ // descendants informed of the removal so any cleanup for active tracking can proceed.
+ mExecutor.execute(() -> mActiveTouchSessions.forEach(touchSession -> {
+ while (touchSession != null) {
+ touchSession.onRemoved();
+ touchSession = touchSession.getPredecessor();
+ }
+ }));
+
mCurrentInputSession.dispose();
mCurrentInputSession = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java
index 4382757..e1d0339 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java
@@ -21,10 +21,10 @@
import android.os.Looper;
import android.view.Choreographer;
-import android.view.Display;
import android.view.GestureDetector;
import android.view.MotionEvent;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -55,8 +55,9 @@
public InputSession(@Named(INPUT_SESSION_NAME) String sessionName,
InputChannelCompat.InputEventListener inputEventListener,
GestureDetector.OnGestureListener gestureListener,
+ DisplayTracker displayTracker,
@Named(PILFER_ON_GESTURE_CONSUME) boolean pilferOnGestureConsume) {
- mInputMonitor = new InputMonitorCompat(sessionName, Display.DEFAULT_DISPLAY);
+ mInputMonitor = new InputMonitorCompat(sessionName, displayTracker.getDefaultDisplayId());
mGestureDetector = new GestureDetector(gestureListener);
mInputEventReceiver = mInputMonitor.getInputReceiver(Looper.getMainLooper(),
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java
new file mode 100644
index 0000000..f5bbba7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerScrimController.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch.scrim;
+
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+
+import javax.inject.Inject;
+
+/**
+ * Implementation for handling swipe movements on the overlay when the keyguard is present.
+ */
+public class BouncerScrimController implements ScrimController {
+ private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+
+ @Inject
+ BouncerScrimController(StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ }
+
+ @Override
+ public void show() {
+ mStatusBarKeyguardViewManager.showBouncer(false);
+ }
+
+ @Override
+ public void expand(ShadeExpansionChangeEvent event) {
+ mStatusBarKeyguardViewManager.onPanelExpansionChanged(event);
+ }
+
+ @Override
+ public void reset() {
+ mStatusBarKeyguardViewManager.reset(false);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimController.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimController.java
new file mode 100644
index 0000000..01e4d04
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimController.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch.scrim;
+
+import android.os.PowerManager;
+import android.os.SystemClock;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.unfold.util.CallbackController;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * {@link BouncerlessScrimController} handles scrim progression when no keyguard is set. When
+ * fully expanded, the controller dismisses the dream.
+ */
+@SysUISingleton
+public class BouncerlessScrimController implements ScrimController,
+ CallbackController<BouncerlessScrimController.Callback> {
+ private static final String TAG = "BLScrimController";
+
+ /**
+ * {@link Callback} allows {@link BouncerlessScrimController} clients to be informed of
+ * expansion progression and wakeup
+ */
+ public interface Callback {
+ /**
+ * Invoked when there is a change to the scrim expansion.
+ */
+ void onExpansion(ShadeExpansionChangeEvent event);
+
+ /**
+ * Invoked after {@link BouncerlessScrimController} has started waking up the device.
+ */
+ void onWakeup();
+ }
+
+ private final Executor mExecutor;
+ private final PowerManager mPowerManager;
+
+ @Override
+ public void addCallback(Callback listener) {
+ mExecutor.execute(() -> mCallbacks.add(listener));
+ }
+
+ @Override
+ public void removeCallback(Callback listener) {
+ mExecutor.execute(() -> mCallbacks.remove(listener));
+ }
+
+ private final HashSet<Callback> mCallbacks;
+
+
+ @Inject
+ public BouncerlessScrimController(@Main Executor executor,
+ PowerManager powerManager) {
+ mExecutor = executor;
+ mPowerManager = powerManager;
+ mCallbacks = new HashSet<>();
+ }
+
+ @Override
+ public void expand(ShadeExpansionChangeEvent event) {
+ if (event.getExpanded()) {
+ mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+ "com.android.systemui:SwipeUp");
+ mExecutor.execute(() -> mCallbacks.forEach(callback -> callback.onWakeup()));
+ } else {
+ mExecutor.execute(() -> mCallbacks.forEach(callback -> callback.onExpansion(event)));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimController.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimController.java
new file mode 100644
index 0000000..61629ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimController.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch.scrim;
+
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+
+/**
+ * {@link ScrimController} provides an interface for the different consumers of scrolling/expansion
+ * events over the dream.
+ */
+public interface ScrimController {
+ /**
+ * Called at the start of expansion before any expansion amount updates.
+ */
+ default void show() {
+ }
+
+ /**
+ * Called for every expansion update.
+ * @param event {@link ShadeExpansionChangeEvent} detailing the change.
+ */
+ default void expand(ShadeExpansionChangeEvent event) {
+ }
+
+ /**
+ * Called at the end of the movement.
+ */
+ default void reset() {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimManager.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimManager.java
new file mode 100644
index 0000000..0d0dff6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/ScrimManager.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.systemui.dreams.touch.scrim;
+
+import static com.android.systemui.dreams.touch.scrim.dagger.ScrimModule.BOUNCERLESS_SCRIM_CONTROLLER;
+import static com.android.systemui.dreams.touch.scrim.dagger.ScrimModule.BOUNCER_SCRIM_CONTROLLER;
+
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * {@link ScrimManager} helps manage multiple {@link ScrimController} instances, specifying the
+ * appropriate one to use at the current moment and managing the handoff between controllers.
+ */
+public class ScrimManager {
+ private final ScrimController mBouncerScrimController;
+ private final ScrimController mBouncerlessScrimController;
+ private final KeyguardStateController mKeyguardStateController;
+ private final Executor mExecutor;
+
+ private ScrimController mCurrentController;
+ private final HashSet<Callback> mCallbacks;
+
+ /**
+ * Interface implemented for receiving updates to the active {@link ScrimController}.
+ */
+ public interface Callback {
+ /**
+ * Invoked when the controller changes.
+ * @param controller The currently active {@link ScrimController}.
+ */
+ void onScrimControllerChanged(ScrimController controller);
+ }
+
+ private final KeyguardStateController.Callback mKeyguardStateCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ mExecutor.execute(() -> updateController());
+ }
+ };
+
+ @Inject
+ ScrimManager(@Main Executor executor,
+ @Named(BOUNCER_SCRIM_CONTROLLER) ScrimController bouncerScrimController,
+ @Named(BOUNCERLESS_SCRIM_CONTROLLER)ScrimController bouncerlessScrimController,
+ KeyguardStateController keyguardStateController) {
+ mExecutor = executor;
+ mCallbacks = new HashSet<>();
+ mBouncerlessScrimController = bouncerlessScrimController;
+ mBouncerScrimController = bouncerScrimController;
+ mKeyguardStateController = keyguardStateController;
+
+ mKeyguardStateController.addCallback(mKeyguardStateCallback);
+ updateController();
+ }
+
+ private void updateController() {
+ final ScrimController existingController = mCurrentController;
+ mCurrentController = mKeyguardStateController.canDismissLockScreen()
+ ? mBouncerlessScrimController
+ : mBouncerScrimController;
+
+ if (existingController == mCurrentController) {
+ return;
+ }
+
+ mCallbacks.forEach(callback -> callback.onScrimControllerChanged(mCurrentController));
+ }
+
+ /**
+ * Adds a {@link Callback} to receive future changes to the active {@link ScrimController}.
+ */
+ public void addCallback(Callback callback) {
+ mExecutor.execute(() -> mCallbacks.add(callback));
+ }
+
+ /**
+ * Removes the {@link Callback} from receiving further updates.
+ */
+ public void removeCallback(Callback callback) {
+ mExecutor.execute(() -> mCallbacks.remove(callback));
+ }
+
+ /**
+ * Returns the currently get {@link ScrimController}.
+ * @return
+ */
+ public ScrimController getCurrentController() {
+ return mCurrentController;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/dagger/ScrimModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/dagger/ScrimModule.java
new file mode 100644
index 0000000..40bc0ea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/scrim/dagger/ScrimModule.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.systemui.dreams.touch.scrim.dagger;
+
+import com.android.systemui.dreams.touch.scrim.BouncerScrimController;
+import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
+import com.android.systemui.dreams.touch.scrim.ScrimController;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Module for scrim related dependencies.
+ */
+@Module
+public interface ScrimModule {
+ String BOUNCERLESS_SCRIM_CONTROLLER = "bouncerless_scrim_controller";
+ String BOUNCER_SCRIM_CONTROLLER = "bouncer_scrim_controller";
+
+ /** */
+ @Provides
+ @Named(BOUNCERLESS_SCRIM_CONTROLLER)
+ static ScrimController providesBouncerlessScrimController(
+ BouncerlessScrimController controller) {
+ return controller;
+ }
+
+ /** */
+ @Provides
+ @Named(BOUNCER_SCRIM_CONTROLLER)
+ static ScrimController providesBouncerScrimController(
+ BouncerScrimController controller) {
+ return controller;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
index b94d781..dc7fc28 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
@@ -21,6 +21,7 @@
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.util.InitializationChecker
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
@@ -34,7 +35,8 @@
private val commandRegistry: CommandRegistry,
private val flagCommand: FlagCommand,
private val featureFlags: FeatureFlagsDebug,
- private val broadcastSender: BroadcastSender
+ private val broadcastSender: BroadcastSender,
+ private val initializationChecker: InitializationChecker
) : CoreStartable {
init {
@@ -46,8 +48,11 @@
override fun start() {
featureFlags.init()
commandRegistry.registerCommand(FlagCommand.FLAG_COMMAND) { flagCommand }
- val intent = Intent(FlagManager.ACTION_SYSUI_STARTED)
- broadcastSender.sendBroadcast(intent)
+ if (initializationChecker.initializeComponents()) {
+ // protected broadcast should only be sent for the main process
+ val intent = Intent(FlagManager.ACTION_SYSUI_STARTED)
+ broadcastSender.sendBroadcast(intent)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index af12529..47c41fe 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -198,8 +198,7 @@
/** A different path for unocclusion transitions back to keyguard */
// TODO(b/262859270): Tracking Bug
- @JvmField
- val UNOCCLUSION_TRANSITION = unreleasedFlag(223, "unocclusion_transition", teamfood = true)
+ @JvmField val UNOCCLUSION_TRANSITION = releasedFlag(223, "unocclusion_transition")
// flag for controlling auto pin confirmation and material u shapes in bouncer
@JvmField
@@ -220,6 +219,15 @@
val WALLPAPER_FULLSCREEN_PREVIEW =
unreleasedFlag(227, "wallpaper_fullscreen_preview", teamfood = true)
+ /** Whether the long-press gesture to open wallpaper picker is enabled. */
+ // TODO(b/266242192): Tracking Bug
+ @JvmField
+ val LOCK_SCREEN_LONG_PRESS_ENABLED =
+ unreleasedFlag(
+ 228,
+ "lock_screen_long_press_enabled",
+ )
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -438,6 +446,18 @@
teamfood = false
)
+ // TODO(b/198643358): Tracking bug
+ @Keep
+ @JvmField
+ val ENABLE_PIP_SIZE_LARGE_SCREEN =
+ sysPropBooleanFlag(1114, "persist.wm.debug.enable_pip_size_large_screen", default = false)
+
+ // TODO(b/265998256): Tracking bug
+ @Keep
+ @JvmField
+ val ENABLE_PIP_APP_ICON_OVERLAY =
+ sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = false)
+
// 1200 - predictive back
@Keep
@JvmField
@@ -514,7 +534,6 @@
unreleasedFlag(1600, "a11y_floating_menu_fling_spring_animations")
// 1700 - clipboard
- @JvmField val CLIPBOARD_OVERLAY_REFACTOR = releasedFlag(1700, "clipboard_overlay_refactor")
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
// 1800 - shade container
@@ -527,7 +546,7 @@
@JvmField val NOTE_TASKS = unreleasedFlag(1900, "keycode_flag")
// 2000 - device controls
- @Keep @JvmField val USE_APP_PANELS = unreleasedFlag(2000, "use_app_panels", teamfood = true)
+ @Keep @JvmField val USE_APP_PANELS = releasedFlag(2000, "use_app_panels", teamfood = true)
@JvmField
val APP_PANELS_ALL_APPS_ALLOWED =
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
index 18fb423..98896b1 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/ExtensionFragmentListener.java
@@ -37,9 +37,14 @@
private final int mId;
private String mOldClass;
- private ExtensionFragmentListener(View view, String tag, int id, Extension<T> extension) {
+ private ExtensionFragmentListener(
+ FragmentService fragmentService,
+ View view,
+ String tag,
+ int id,
+ Extension<T> extension) {
mTag = tag;
- mFragmentHostManager = FragmentHostManager.get(view);
+ mFragmentHostManager = fragmentService.getFragmentHostManager(view);
mExtension = extension;
mId = id;
mFragmentHostManager.getFragmentManager().beginTransaction()
@@ -61,8 +66,13 @@
mExtension.clearItem(true);
}
- public static <T> void attachExtensonToFragment(View view, String tag, int id,
+ public static <T> void attachExtensonToFragment(
+ FragmentService fragmentService,
+ View view,
+ String tag,
+ int id,
Extension<T> extension) {
- extension.addCallback(new ExtensionFragmentListener(view, tag, id, extension));
+ extension.addCallback(
+ new ExtensionFragmentListener(fragmentService, view, tag, id, extension));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 9c7411b..6a27ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -36,7 +36,6 @@
import androidx.annotation.NonNull;
import com.android.settingslib.applications.InterestingConfigChanges;
-import com.android.systemui.Dependency;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.util.leak.LeakDetector;
@@ -46,12 +45,17 @@
import java.util.ArrayList;
import java.util.HashMap;
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
public class FragmentHostManager {
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final Context mContext;
private final HashMap<String, ArrayList<FragmentListener>> mListeners = new HashMap<>();
private final View mRootView;
+ private final LeakDetector mLeakDetector;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
| ActivityInfo.CONFIG_ASSETS_PATHS);
@@ -61,14 +65,24 @@
private FragmentController mFragments;
private FragmentLifecycleCallbacks mLifecycleCallbacks;
- FragmentHostManager(FragmentService manager, View rootView) {
+ @AssistedInject
+ FragmentHostManager(
+ @Assisted View rootView,
+ FragmentService manager,
+ LeakDetector leakDetector) {
mContext = rootView.getContext();
mManager = manager;
mRootView = rootView;
+ mLeakDetector = leakDetector;
mConfigChanges.applyNewConfig(mContext.getResources());
createFragmentHost(null);
}
+ @AssistedFactory
+ public interface Factory {
+ FragmentHostManager create(View rootView);
+ }
+
private void createFragmentHost(Parcelable savedState) {
mFragments = FragmentController.createController(new HostCallbacks());
mFragments.attachHost(null);
@@ -86,7 +100,7 @@
@Override
public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
- Dependency.get(LeakDetector.class).trackGarbage(f);
+ mLeakDetector.trackGarbage(f);
}
};
mFragments.getFragmentManager().registerFragmentLifecycleCallbacks(mLifecycleCallbacks,
@@ -211,19 +225,6 @@
}
}
- public static FragmentHostManager get(View view) {
- try {
- return Dependency.get(FragmentService.class).getFragmentHostManager(view);
- } catch (ClassCastException e) {
- // TODO: Some auto handling here?
- throw e;
- }
- }
-
- public static void removeAndDestroy(View view) {
- Dependency.get(FragmentService.class).removeAndDestroy(view);
- }
-
public void reloadFragments() {
Trace.beginSection("FrargmentHostManager#reloadFragments");
// Save the old state.
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index fe945fb..d302b13a 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -53,6 +53,7 @@
*/
private final ArrayMap<String, FragmentInstantiationInfo> mInjectionMap = new ArrayMap<>();
private final Handler mHandler = new Handler();
+ private final FragmentHostManager.Factory mFragmentHostManagerFactory;
private ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@@ -67,8 +68,10 @@
@Inject
public FragmentService(
FragmentCreator.Factory fragmentCreatorFactory,
+ FragmentHostManager.Factory fragmentHostManagerFactory,
ConfigurationController configurationController,
DumpManager dumpManager) {
+ mFragmentHostManagerFactory = fragmentHostManagerFactory;
addFragmentInstantiationProvider(fragmentCreatorFactory.build());
configurationController.addCallback(mConfigurationListener);
@@ -152,7 +155,7 @@
public FragmentHostState(View view) {
mView = view;
- mFragmentHostManager = new FragmentHostManager(FragmentService.this, mView);
+ mFragmentHostManager = mFragmentHostManagerFactory.create(mView);
}
public void sendConfigurationChange(Configuration newConfig) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 482138e..680c504 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -31,10 +31,12 @@
import android.util.Log
import com.android.systemui.SystemUIAppComponentFactoryBase
import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.ui.preview.KeyguardRemotePreviewManager
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract as Contract
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.runBlocking
class CustomizationProvider :
@@ -42,6 +44,7 @@
@Inject lateinit var interactor: KeyguardQuickAffordanceInteractor
@Inject lateinit var previewManager: KeyguardRemotePreviewManager
+ @Inject @Main lateinit var mainDispatcher: CoroutineDispatcher
private lateinit var contextAvailableCallback: ContextAvailableCallback
@@ -138,12 +141,14 @@
selectionArgs: Array<out String>?,
sortOrder: String?,
): Cursor? {
- return when (uriMatcher.match(uri)) {
- MATCH_CODE_ALL_AFFORDANCES -> runBlocking { queryAffordances() }
- MATCH_CODE_ALL_SLOTS -> querySlots()
- MATCH_CODE_ALL_SELECTIONS -> runBlocking { querySelections() }
- MATCH_CODE_ALL_FLAGS -> queryFlags()
- else -> null
+ return runBlocking(mainDispatcher) {
+ when (uriMatcher.match(uri)) {
+ MATCH_CODE_ALL_AFFORDANCES -> queryAffordances()
+ MATCH_CODE_ALL_SLOTS -> querySlots()
+ MATCH_CODE_ALL_SELECTIONS -> querySelections()
+ MATCH_CODE_ALL_FLAGS -> queryFlags()
+ else -> null
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index f4a1227..47872d2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -17,7 +17,6 @@
package com.android.systemui.keyguard;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.TRANSIT_CLOSE;
@@ -80,6 +79,7 @@
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.keyguard.mediator.ScreenOnCoordinator;
import com.android.systemui.SystemUIApplication;
+import com.android.systemui.settings.DisplayTracker;
import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -123,6 +123,7 @@
private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher;
private final ScreenOnCoordinator mScreenOnCoordinator;
private final ShellTransitions mShellTransitions;
+ private final DisplayTracker mDisplayTracker;
private static int newModeToLegacyMode(int newMode) {
switch (newMode) {
@@ -286,12 +287,14 @@
public KeyguardService(KeyguardViewMediator keyguardViewMediator,
KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
ScreenOnCoordinator screenOnCoordinator,
- ShellTransitions shellTransitions) {
+ ShellTransitions shellTransitions,
+ DisplayTracker displayTracker) {
super();
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
mScreenOnCoordinator = screenOnCoordinator;
mShellTransitions = shellTransitions;
+ mDisplayTracker = displayTracker;
}
@Override
@@ -328,7 +331,7 @@
unoccludeAnimationAdapter);
}
ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
- DEFAULT_DISPLAY, definition);
+ mDisplayTracker.getDefaultDisplayId(), definition);
return;
}
if (sEnableRemoteKeyguardGoingAwayAnimation) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index f6e6d6b..5a9f775 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -19,6 +19,7 @@
import android.app.StatusBarManager
import android.content.Context
+import android.content.pm.PackageManager
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.camera.CameraGestureHelper
@@ -26,7 +27,6 @@
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.statusbar.StatusBarState
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -37,6 +37,7 @@
@Inject
constructor(
@Application private val context: Context,
+ private val packageManager: PackageManager,
private val cameraGestureHelper: Lazy<CameraGestureHelper>,
) : KeyguardQuickAffordanceConfig {
@@ -79,6 +80,6 @@
}
private fun isLaunchable(): Boolean {
- return cameraGestureHelper.get().canCameraGestureBeLaunched(StatusBarState.KEYGUARD)
+ return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index 08edbc6..b3a9cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -22,14 +22,18 @@
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
/** Encapsulates state about device entry fingerprint auth mechanism. */
interface DeviceEntryFingerprintAuthRepository {
/** Whether the device entry fingerprint auth is locked out. */
- val isLockedOut: Flow<Boolean>
+ val isLockedOut: StateFlow<Boolean>
}
/**
@@ -44,29 +48,34 @@
@Inject
constructor(
val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ @Application scope: CoroutineScope,
) : DeviceEntryFingerprintAuthRepository {
- override val isLockedOut: Flow<Boolean> = conflatedCallbackFlow {
- val sendLockoutUpdate =
- fun() {
- trySendWithFailureLogging(
- keyguardUpdateMonitor.isFingerprintLockedOut,
- TAG,
- "onLockedOutStateChanged"
- )
- }
- val callback =
- object : KeyguardUpdateMonitorCallback() {
- override fun onLockedOutStateChanged(biometricSourceType: BiometricSourceType?) {
- if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
- sendLockoutUpdate()
+ override val isLockedOut: StateFlow<Boolean> =
+ conflatedCallbackFlow {
+ val sendLockoutUpdate =
+ fun() {
+ trySendWithFailureLogging(
+ keyguardUpdateMonitor.isFingerprintLockedOut,
+ TAG,
+ "onLockedOutStateChanged"
+ )
}
- }
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onLockedOutStateChanged(
+ biometricSourceType: BiometricSourceType?
+ ) {
+ if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
+ sendLockoutUpdate()
+ }
+ }
+ }
+ keyguardUpdateMonitor.registerCallback(callback)
+ sendLockoutUpdate()
+ awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
- keyguardUpdateMonitor.registerCallback(callback)
- sendLockoutUpdate()
- awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
- }
+ .stateIn(scope, started = SharingStarted.Eagerly, initialValue = false)
companion object {
const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
index 41574d1..3e17136 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardBouncerRepository.kt
@@ -26,7 +26,6 @@
import com.android.systemui.log.dagger.BouncerLog
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
-import com.android.systemui.statusbar.phone.KeyguardBouncer
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index d99af90..db95562 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -148,6 +148,9 @@
/** Source of the most recent biometric unlock, such as fingerprint or face. */
val biometricUnlockSource: Flow<BiometricUnlockSource?>
+ /** Whether quick settings or quick-quick settings is visible. */
+ val isQuickSettingsVisible: Flow<Boolean>
+
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
*
@@ -172,6 +175,9 @@
* Returns whether the keyguard bottom area should be constrained to the top of the lock icon
*/
fun isUdfpsSupported(): Boolean
+
+ /** Sets whether quick settings or quick-quick settings is visible. */
+ fun setQuickSettingsVisible(isVisible: Boolean)
}
/** Encapsulates application state for the keyguard. */
@@ -581,6 +587,9 @@
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
+ private val _isQuickSettingsVisible = MutableStateFlow(false)
+ override val isQuickSettingsVisible: Flow<Boolean> = _isQuickSettingsVisible.asStateFlow()
+
override fun setAnimateDozingTransitions(animate: Boolean) {
_animateBottomAreaDozingTransitions.value = animate
}
@@ -595,6 +604,10 @@
override fun isUdfpsSupported(): Boolean = keyguardUpdateMonitor.isUdfpsSupported
+ override fun setQuickSettingsVisible(isVisible: Boolean) {
+ _isQuickSettingsVisible.value = isVisible
+ }
+
private fun statusBarStateIntToObject(value: Int): StatusBarState {
return when (value) {
0 -> StatusBarState.SHADE
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 4639597..cc99eb7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -32,4 +32,9 @@
fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
@Binds fun biometricRepository(impl: BiometricRepositoryImpl): BiometricRepository
+
+ @Binds
+ fun deviceEntryFingerprintAuthRepository(
+ impl: DeviceEntryFingerprintAuthRepositoryImpl
+ ): DeviceEntryFingerprintAuthRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index 28c0b28..6020ef8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -21,6 +21,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.BiometricRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager.LegacyAlternateBouncer
import com.android.systemui.util.time.SystemClock
@@ -34,6 +35,7 @@
constructor(
private val bouncerRepository: KeyguardBouncerRepository,
private val biometricRepository: BiometricRepository,
+ private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
private val systemClock: SystemClock,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
featureFlags: FeatureFlags,
@@ -99,7 +101,8 @@
bouncerRepository.isAlternateBouncerUIAvailable.value &&
biometricRepository.isFingerprintEnrolled.value &&
biometricRepository.isStrongBiometricAllowed.value &&
- biometricRepository.isFingerprintEnabledByDevicePolicy.value
+ biometricRepository.isFingerprintEnabledByDevicePolicy.value &&
+ !deviceEntryFingerprintAuthRepository.isLockedOut.value
} else {
legacyAlternateBouncer != null &&
keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(true)
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 4cf56fe..3d39da6 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
@@ -155,6 +155,11 @@
}
}
+ /** Sets whether quick settings or quick-quick settings is visible. */
+ fun setQuickSettingsVisible(isVisible: Boolean) {
+ repository.setQuickSettingsVisible(isVisible)
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt
new file mode 100644
index 0000000..6525a13
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractor.kt
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.common.shared.model.Position
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.domain.model.KeyguardSettingsPopupMenuModel
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.plugins.ActivityStarter
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+/** Business logic for use-cases related to the keyguard long-press feature. */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class KeyguardLongPressInteractor
+@Inject
+constructor(
+ @Application unsafeContext: Context,
+ @Application scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ repository: KeyguardRepository,
+ private val activityStarter: ActivityStarter,
+ private val logger: UiEventLogger,
+ private val featureFlags: FeatureFlags,
+ broadcastDispatcher: BroadcastDispatcher,
+) {
+ private val appContext = unsafeContext.applicationContext
+
+ private val _isLongPressHandlingEnabled: StateFlow<Boolean> =
+ if (isFeatureEnabled()) {
+ combine(
+ transitionInteractor.finishedKeyguardState.map {
+ it == KeyguardState.LOCKSCREEN
+ },
+ repository.isQuickSettingsVisible,
+ ) { isFullyTransitionedToLockScreen, isQuickSettingsVisible ->
+ isFullyTransitionedToLockScreen && !isQuickSettingsVisible
+ }
+ } else {
+ flowOf(false)
+ }
+ .stateIn(
+ scope = scope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false,
+ )
+
+ /** Whether the long-press handling feature should be enabled. */
+ val isLongPressHandlingEnabled: Flow<Boolean> = _isLongPressHandlingEnabled
+
+ private val _menu = MutableStateFlow<KeyguardSettingsPopupMenuModel?>(null)
+ /** Model for a menu that should be shown; `null` when no menu should be shown. */
+ val menu: Flow<KeyguardSettingsPopupMenuModel?> =
+ isLongPressHandlingEnabled.flatMapLatest { isEnabled ->
+ if (isEnabled) {
+ _menu
+ } else {
+ flowOf(null)
+ }
+ }
+
+ init {
+ if (isFeatureEnabled()) {
+ broadcastDispatcher
+ .broadcastFlow(
+ IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
+ )
+ .onEach { hideMenu() }
+ .launchIn(scope)
+ }
+ }
+
+ /** Notifies that the user has long-pressed on the lock screen. */
+ fun onLongPress(x: Int, y: Int) {
+ if (!_isLongPressHandlingEnabled.value) {
+ return
+ }
+
+ showMenu(
+ x = x,
+ y = y,
+ )
+ }
+
+ private fun isFeatureEnabled(): Boolean {
+ return featureFlags.isEnabled(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED) &&
+ featureFlags.isEnabled(Flags.REVAMPED_WALLPAPER_UI)
+ }
+
+ /** Updates application state to ask to show the menu at the given coordinates. */
+ private fun showMenu(
+ x: Int,
+ y: Int,
+ ) {
+ _menu.value =
+ KeyguardSettingsPopupMenuModel(
+ position =
+ Position(
+ x = x,
+ y = y,
+ ),
+ onClicked = {
+ hideMenu()
+ navigateToLockScreenSettings()
+ },
+ onDismissed = { hideMenu() },
+ )
+ logger.log(LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_SHOWN)
+ }
+
+ /** Updates application state to ask to hide the menu. */
+ private fun hideMenu() {
+ _menu.value = null
+ }
+
+ /** Opens the wallpaper picker screen after the device is unlocked by the user. */
+ private fun navigateToLockScreenSettings() {
+ logger.log(LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_CLICKED)
+ activityStarter.dismissKeyguardThenExecute(
+ /* action= */ {
+ appContext.startActivity(
+ Intent(Intent.ACTION_SET_WALLPAPER).apply {
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ appContext
+ .getString(R.string.config_wallpaperPickerPackage)
+ .takeIf { it.isNotEmpty() }
+ ?.let { packageName -> setPackage(packageName) }
+ }
+ )
+ true
+ },
+ /* cancel= */ {},
+ /* afterKeyguardGone= */ true,
+ )
+ }
+
+ enum class LogEvents(
+ private val _id: Int,
+ ) : UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "The lock screen was long-pressed and we showed the settings popup menu.")
+ LOCK_SCREEN_LONG_PRESS_POPUP_SHOWN(1292),
+ @UiEvent(doc = "The lock screen long-press popup menu was clicked.")
+ LOCK_SCREEN_LONG_PRESS_POPUP_CLICKED(1293),
+ ;
+
+ override fun getId() = _id
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardSettingsPopupMenuModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardSettingsPopupMenuModel.kt
new file mode 100644
index 0000000..7c61e71
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardSettingsPopupMenuModel.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.model
+
+import com.android.systemui.common.shared.model.Position
+
+/** Models a settings popup menu for the lock screen. */
+data class KeyguardSettingsPopupMenuModel(
+ /** Where the menu should be anchored, roughly in screen space. */
+ val position: Position,
+ /** Callback to invoke when the menu gets clicked by the user. */
+ val onClicked: () -> Unit,
+ /** Callback to invoke when the menu gets dismissed by the user. */
+ val onDismissed: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
index bb5ac84..8222dd5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/constants/KeyguardBouncerConstants.kt
@@ -25,4 +25,5 @@
*/
const val EXPANSION_HIDDEN = 1f
const val EXPANSION_VISIBLE = 0f
+ const val ALPHA_EXPANSION_THRESHOLD = 0.95f
}
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 e9d7a5b..3319f9d 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
@@ -49,6 +49,7 @@
import kotlin.math.sqrt
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
@@ -163,12 +164,26 @@
ambientIndicationArea?.alpha = alpha
indicationArea.alpha = alpha
- startButton.alpha = alpha
- endButton.alpha = alpha
}
}
launch {
+ updateButtonAlpha(
+ view = startButton,
+ viewModel = viewModel.startButton,
+ alphaFlow = viewModel.alpha,
+ )
+ }
+
+ launch {
+ updateButtonAlpha(
+ view = endButton,
+ viewModel = viewModel.endButton,
+ alphaFlow = viewModel.alpha,
+ )
+ }
+
+ launch {
viewModel.indicationAreaTranslationX.collect { translationX ->
indicationArea.translationX = translationX
ambientIndicationArea?.translationX = translationX
@@ -321,7 +336,6 @@
.animate()
.scaleX(if (viewModel.isSelected) SCALE_SELECTED_BUTTON else 1f)
.scaleY(if (viewModel.isSelected) SCALE_SELECTED_BUTTON else 1f)
- .alpha(if (viewModel.isDimmed) DIM_ALPHA else 1f)
.start()
view.isClickable = viewModel.isClickable
@@ -341,6 +355,17 @@
view.isSelected = viewModel.isSelected
}
+ private suspend fun updateButtonAlpha(
+ view: View,
+ viewModel: Flow<KeyguardQuickAffordanceViewModel>,
+ alphaFlow: Flow<Float>,
+ ) {
+ combine(viewModel.map { it.isDimmed }, alphaFlow) { isDimmed, alpha ->
+ if (isDimmed) DIM_ALPHA else alpha
+ }
+ .collect { view.alpha = it }
+ }
+
private class OnTouchListener(
private val view: View,
private val viewModel: KeyguardQuickAffordanceViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressPopupViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressPopupViewBinder.kt
new file mode 100644
index 0000000..d85682b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressPopupViewBinder.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.annotation.SuppressLint
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.WindowManager
+import android.widget.PopupWindow
+import com.android.systemui.R
+import com.android.systemui.common.ui.binder.IconViewBinder
+import com.android.systemui.common.ui.binder.TextViewBinder
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSettingsPopupMenuViewModel
+
+object KeyguardLongPressPopupViewBinder {
+ @SuppressLint("InflateParams") // We don't care that the parent is null.
+ fun createAndShow(
+ container: View,
+ viewModel: KeyguardSettingsPopupMenuViewModel,
+ onDismissed: () -> Unit,
+ ): () -> Unit {
+ val contentView: View =
+ LayoutInflater.from(container.context)
+ .inflate(
+ R.layout.keyguard_settings_popup_menu,
+ null,
+ )
+
+ contentView.setOnClickListener { viewModel.onClicked() }
+ IconViewBinder.bind(
+ icon = viewModel.icon,
+ view = contentView.requireViewById(R.id.icon),
+ )
+ TextViewBinder.bind(
+ view = contentView.requireViewById(R.id.text),
+ viewModel = viewModel.text,
+ )
+
+ val popupWindow =
+ PopupWindow(container.context).apply {
+ windowLayoutType = WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
+ setBackgroundDrawable(null)
+ animationStyle = com.android.internal.R.style.Animation_Dialog
+ isOutsideTouchable = true
+ isFocusable = true
+ setContentView(contentView)
+ setOnDismissListener { onDismissed() }
+ contentView.measure(
+ View.MeasureSpec.makeMeasureSpec(
+ 0,
+ View.MeasureSpec.UNSPECIFIED,
+ ),
+ View.MeasureSpec.makeMeasureSpec(
+ 0,
+ View.MeasureSpec.UNSPECIFIED,
+ ),
+ )
+ showAtLocation(
+ container,
+ Gravity.NO_GRAVITY,
+ viewModel.position.x - contentView.measuredWidth / 2,
+ viewModel.position.y -
+ contentView.measuredHeight -
+ container.context.resources.getDimensionPixelSize(
+ R.dimen.keyguard_long_press_settings_popup_vertical_offset
+ ),
+ )
+ }
+
+ return { popupWindow.dismiss() }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
new file mode 100644
index 0000000..ef3f242
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.view.View
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.common.ui.view.LongPressHandlingView
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.plugins.FalsingManager
+import kotlinx.coroutines.launch
+
+object KeyguardLongPressViewBinder {
+ /**
+ * Drives UI for the lock screen long-press feature.
+ *
+ * @param view The view that listens for long-presses.
+ * @param viewModel The view-model that models the UI state.
+ * @param onSingleTap A callback to invoke when the system decides that there was a single tap.
+ * @param falsingManager [FalsingManager] for making sure the long-press didn't just happen in
+ * the user's pocket.
+ */
+ @JvmStatic
+ fun bind(
+ view: LongPressHandlingView,
+ viewModel: KeyguardLongPressViewModel,
+ onSingleTap: () -> Unit,
+ falsingManager: FalsingManager,
+ ) {
+ view.listener =
+ object : LongPressHandlingView.Listener {
+ override fun onLongPressDetected(view: View, x: Int, y: Int) {
+ if (falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) {
+ return
+ }
+
+ viewModel.onLongPress(
+ x = x,
+ y = y,
+ )
+ }
+
+ override fun onSingleTapDetected(view: View) {
+ if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+ return
+ }
+
+ onSingleTap()
+ }
+ }
+
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.isLongPressHandlingEnabled.collect { isEnabled ->
+ view.setLongPressHandlingEnabled(isEnabled)
+ }
+ }
+
+ launch {
+ var dismissMenu: (() -> Unit)? = null
+
+ viewModel.menu.collect { menuOrNull ->
+ if (menuOrNull != null) {
+ dismissMenu =
+ KeyguardLongPressPopupViewBinder.createAndShow(
+ container = view,
+ viewModel = menuOrNull,
+ onDismissed = menuOrNull.onDismissed,
+ )
+ } else {
+ dismissMenu?.invoke()
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt
new file mode 100644
index 0000000..d896390
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardLongPressViewModel.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.R
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** Models UI state to support the lock screen long-press feature. */
+class KeyguardLongPressViewModel
+@Inject
+constructor(
+ private val interactor: KeyguardLongPressInteractor,
+) {
+
+ /** Whether the long-press handling feature should be enabled. */
+ val isLongPressHandlingEnabled: Flow<Boolean> = interactor.isLongPressHandlingEnabled
+
+ /** View-model for a menu that should be shown; `null` when no menu should be shown. */
+ val menu: Flow<KeyguardSettingsPopupMenuViewModel?> =
+ interactor.menu.map { model ->
+ model?.let {
+ KeyguardSettingsPopupMenuViewModel(
+ icon =
+ Icon.Resource(
+ res = R.drawable.ic_settings,
+ contentDescription = null,
+ ),
+ text =
+ Text.Resource(
+ res = R.string.lock_screen_settings,
+ ),
+ position = model.position,
+ onClicked = model.onClicked,
+ onDismissed = model.onDismissed,
+ )
+ }
+ }
+
+ /** Notifies that the user has long-pressed on the lock screen. */
+ fun onLongPress(
+ x: Int,
+ y: Int,
+ ) {
+ interactor.onLongPress(
+ x = x,
+ y = y,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsPopupMenuViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsPopupMenuViewModel.kt
new file mode 100644
index 0000000..0571b05
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSettingsPopupMenuViewModel.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.common.shared.model.Icon
+import com.android.systemui.common.shared.model.Position
+import com.android.systemui.common.shared.model.Text
+
+/** Models the UI state of a keyguard settings popup menu. */
+data class KeyguardSettingsPopupMenuViewModel(
+ val icon: Icon,
+ val text: Text,
+ /** Where the menu should be anchored, roughly in screen space. */
+ val position: Position,
+ /** Callback to invoke when the menu gets clicked by the user. */
+ val onClicked: () -> Unit,
+ /** Callback to invoke when the menu gets dismissed by the user. */
+ val onDismissed: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 51b5a3d..769e0c8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -16,17 +16,21 @@
package com.android.systemui.media.dialog;
+import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
+import androidx.annotation.DoNotInline;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.core.widget.CompoundButtonCompat;
import androidx.recyclerview.widget.RecyclerView;
@@ -186,6 +190,17 @@
mCurrentActivePosition = position;
updateFullItemClickListener(v -> onItemClick(v, device));
setSingleLineLayout(getItemTitle(device));
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
+ && mController.isSubStatusSupported() && device.hasDisabledReason()) {
+ //update to subtext with device status
+ setUpDeviceIcon(device);
+ mSubTitleText.setText(
+ Api34Impl.composeDisabledReason(device.getDisableReason(), mContext));
+ updateConnectionFailedStatusIcon();
+ updateFullItemClickListener(null);
+ setTwoLineLayout(device, false /* bFocused */, false /* showSeekBar */,
+ false /* showProgressBar */, true /* showSubtitle */,
+ true /* showStatus */);
} else if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
setUpDeviceIcon(device);
updateConnectionFailedStatusIcon();
@@ -389,4 +404,12 @@
mTitleText.setText(groupDividerTitle);
}
}
+
+ @RequiresApi(34)
+ private static class Api34Impl {
+ @DoNotInline
+ static String composeDisabledReason(int reason, Context context) {
+ return "";
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 4e08050..dc75538 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -45,6 +45,7 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settingslib.Utils;
@@ -142,11 +143,12 @@
final TextView mVolumeValueText;
final ImageView mTitleIcon;
final ProgressBar mProgressBar;
- final MediaOutputSeekbar mSeekBar;
final LinearLayout mTwoLineLayout;
final ImageView mStatusIcon;
final CheckBox mCheckBox;
final ViewGroup mEndTouchArea;
+ @VisibleForTesting
+ MediaOutputSeekbar mSeekBar;
private String mDeviceId;
private ValueAnimator mCornerAnimator;
private ValueAnimator mVolumeAnimator;
@@ -390,6 +392,7 @@
mTitleIcon.setVisibility(View.VISIBLE);
mVolumeValueText.setVisibility(View.GONE);
}
+ mController.logInteractionAdjustVolume(device);
mIsDragging = false;
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index f95da27..5f5c686 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -141,7 +141,7 @@
@VisibleForTesting
LocalMediaManager mLocalMediaManager;
@VisibleForTesting
- private MediaOutputMetricLogger mMetricLogger;
+ MediaOutputMetricLogger mMetricLogger;
private int mCurrentState;
private int mColorItemContent;
@@ -757,6 +757,10 @@
return mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_ROUTES_PROCESSING);
}
+ public boolean isSubStatusSupported() {
+ return mFeatureFlags.isEnabled(Flags.OUTPUT_SWITCHER_DEVICE_STATUS);
+ }
+
List<MediaDevice> getGroupMediaDevices() {
final List<MediaDevice> selectedDevices = getSelectedMediaDevice();
final List<MediaDevice> selectableDevices = getSelectableMediaDevice();
@@ -866,12 +870,15 @@
}
void adjustVolume(MediaDevice device, int volume) {
- mMetricLogger.logInteractionAdjustVolume(device);
ThreadUtils.postOnBackgroundThread(() -> {
device.requestSetVolume(volume);
});
}
+ void logInteractionAdjustVolume(MediaDevice device) {
+ mMetricLogger.logInteractionAdjustVolume(device);
+ }
+
String getPackageName() {
return mPackageName;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
index b2a5e35..89ca5d3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinator.kt
@@ -23,9 +23,11 @@
import com.android.internal.logging.UiEventLogger
import com.android.internal.statusbar.IUndoMediaTransferCallback
import com.android.systemui.CoreStartable
+import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.common.shared.model.Text
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.media.taptotransfer.common.MediaTttUtils
import com.android.systemui.statusbar.CommandQueue
@@ -34,6 +36,7 @@
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.ChipbarEndItem
import com.android.systemui.temporarydisplay.chipbar.ChipbarInfo
+import java.io.PrintWriter
import javax.inject.Inject
/**
@@ -47,14 +50,13 @@
private val chipbarCoordinator: ChipbarCoordinator,
private val commandQueue: CommandQueue,
private val context: Context,
+ private val dumpManager: DumpManager,
private val logger: MediaTttSenderLogger,
private val mediaTttFlags: MediaTttFlags,
private val uiEventLogger: MediaTttSenderUiEventLogger,
-) : CoreStartable {
+) : CoreStartable, Dumpable {
- private var displayedState: ChipStateSender? = null
// A map to store current chip state per id.
- // TODO(b/265455911): Log whenever we add or remove from the store.
private var stateMap: MutableMap<String, ChipStateSender> = mutableMapOf()
private val commandQueueCallbacks =
@@ -75,6 +77,7 @@
override fun start() {
if (mediaTttFlags.isMediaTttEnabled()) {
commandQueue.addCallback(commandQueueCallbacks)
+ dumpManager.registerNormalDumpable(this)
}
}
@@ -92,11 +95,11 @@
return
}
- val currentState = stateMap[routeInfo.id]
- if (!ChipStateSender.isValidStateTransition(currentState, chipState)) {
+ val currentStateForId: ChipStateSender? = stateMap[routeInfo.id]
+ if (!ChipStateSender.isValidStateTransition(currentStateForId, chipState)) {
// ChipStateSender.FAR_FROM_RECEIVER is the default state when there is no state.
logger.logInvalidStateTransitionError(
- currentState = currentState?.name ?: ChipStateSender.FAR_FROM_RECEIVER.name,
+ currentState = currentStateForId?.name ?: ChipStateSender.FAR_FROM_RECEIVER.name,
chipState.name
)
return
@@ -104,30 +107,29 @@
uiEventLogger.logSenderStateChange(chipState)
if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
- // No need to store the state since it is the default state
- removeIdFromStore(routeInfo.id)
- // Return early if we're not displaying a chip anyway
- val currentDisplayedState = displayedState ?: return
+ // Return early if we're not displaying a chip for this ID anyway
+ if (currentStateForId == null) return
val removalReason = ChipStateSender.FAR_FROM_RECEIVER.name
if (
- currentDisplayedState.transferStatus == TransferStatus.IN_PROGRESS ||
- currentDisplayedState.transferStatus == TransferStatus.SUCCEEDED
+ currentStateForId.transferStatus == TransferStatus.IN_PROGRESS ||
+ currentStateForId.transferStatus == TransferStatus.SUCCEEDED
) {
// Don't remove the chip if we're in progress or succeeded, since the user should
// still be able to see the status of the transfer.
logger.logRemovalBypass(
removalReason,
- bypassReason = "transferStatus=${currentDisplayedState.transferStatus.name}"
+ bypassReason = "transferStatus=${currentStateForId.transferStatus.name}"
)
return
}
- displayedState = null
+ // No need to store the state since it is the default state
+ removeIdFromStore(routeInfo.id, reason = removalReason)
chipbarCoordinator.removeView(routeInfo.id, removalReason)
} else {
stateMap[routeInfo.id] = chipState
- displayedState = chipState
+ logger.logStateMap(stateMap)
chipbarCoordinator.registerListener(displayListener)
chipbarCoordinator.displayView(
createChipbarInfo(
@@ -232,12 +234,19 @@
}
private val displayListener =
- TemporaryViewDisplayController.Listener { id -> removeIdFromStore(id) }
+ TemporaryViewDisplayController.Listener { id, reason -> removeIdFromStore(id, reason) }
- private fun removeIdFromStore(id: String) {
+ private fun removeIdFromStore(id: String, reason: String) {
+ logger.logStateMapRemoval(id, reason)
stateMap.remove(id)
+ logger.logStateMap(stateMap)
if (stateMap.isEmpty()) {
chipbarCoordinator.unregisterListener(displayListener)
}
}
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println("Current sender states:")
+ pw.println(stateMap.toString())
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
index 6363425..964a95b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
@@ -85,6 +85,29 @@
)
}
+ /** Logs the current contents of the state map. */
+ fun logStateMap(map: Map<String, ChipStateSender>) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = map.toString() },
+ { "Current sender states: $str1" }
+ )
+ }
+
+ /** Logs that [id] has been removed from the state map due to [reason]. */
+ fun logStateMapRemoval(id: String, reason: String) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = id
+ str2 = reason
+ },
+ { "State removal: id=$str1 reason=$str2" }
+ )
+ }
+
companion object {
private const val TAG = "MediaTttSender"
}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
index 3ecf154..8d80990 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
@@ -16,13 +16,12 @@
package com.android.systemui.model;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import android.annotation.NonNull;
import android.util.Log;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.system.QuickStepContract;
import java.io.PrintWriter;
@@ -39,11 +38,16 @@
private static final String TAG = SysUiState.class.getSimpleName();
public static final boolean DEBUG = false;
+ private final DisplayTracker mDisplayTracker;
private @QuickStepContract.SystemUiStateFlags int mFlags;
private final List<SysUiStateCallback> mCallbacks = new ArrayList<>();
private int mFlagsToSet = 0;
private int mFlagsToClear = 0;
+ public SysUiState(DisplayTracker displayTracker) {
+ mDisplayTracker = displayTracker;
+ }
+
/**
* Add listener to be notified of changes made to SysUI state.
* The callback will also be called as part of this function.
@@ -81,7 +85,7 @@
}
private void updateFlags(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
+ if (displayId != mDisplayTracker.getDefaultDisplayId()) {
// Ignore non-default displays for now
Log.w(TAG, "Ignoring flag update for display: " + displayId, new Throwable());
return;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 5993e2e..97c290d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -25,7 +25,6 @@
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
@@ -130,6 +129,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
@@ -218,6 +218,7 @@
private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener;
private final UserContextProvider mUserContextProvider;
private final WakefulnessLifecycle mWakefulnessLifecycle;
+ private final DisplayTracker mDisplayTracker;
private final RegionSamplingHelper mRegionSamplingHelper;
private final int mNavColorSampleMargin;
private NavigationBarFrame mFrame;
@@ -461,7 +462,8 @@
@Override
public void onStartedWakingUp() {
notifyScreenStateChanged(true);
- if (isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode)) {
+ if (isGesturalModeOnDefaultDisplay(getContext(), mDisplayTracker,
+ mNavBarMode)) {
mRegionSamplingHelper.start(mSamplingBounds);
}
}
@@ -545,7 +547,8 @@
Optional<BackAnimation> backAnimation,
UserContextProvider userContextProvider,
WakefulnessLifecycle wakefulnessLifecycle,
- TaskStackChangeListeners taskStackChangeListeners) {
+ TaskStackChangeListeners taskStackChangeListeners,
+ DisplayTracker displayTracker) {
super(navigationBarView);
mFrame = navigationBarFrame;
mContext = context;
@@ -585,6 +588,7 @@
mUserContextProvider = userContextProvider;
mWakefulnessLifecycle = wakefulnessLifecycle;
mTaskStackChangeListeners = taskStackChangeListeners;
+ mDisplayTracker = displayTracker;
mNavColorSampleMargin = getResources()
.getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
@@ -632,12 +636,14 @@
@Override
public boolean isSamplingEnabled() {
- return isGesturalModeOnDefaultDisplay(getContext(), mNavBarMode);
+ return isGesturalModeOnDefaultDisplay(getContext(), mDisplayTracker,
+ mNavBarMode);
}
}, mainExecutor, bgExecutor);
mView.setBackgroundExecutor(bgExecutor);
mView.setEdgeBackGestureHandler(mEdgeBackGestureHandler);
+ mView.setDisplayTracker(mDisplayTracker);
mNavBarMode = mNavigationModeController.addListener(mModeChangedListener);
}
@@ -665,7 +671,7 @@
getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
.getRotation()));
mDisplayId = mContext.getDisplayId();
- mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
+ mIsOnDefaultDisplay = mDisplayId == mDisplayTracker.getDefaultDisplayId();
// Ensure we try to get currentSysuiState from navBarHelper before command queue callbacks
// start firing, since the latter is source of truth
@@ -1468,7 +1474,7 @@
private void onAccessibilityClick(View v) {
final Display display = v.getDisplay();
mAccessibilityManager.notifyAccessibilityButtonClicked(
- display != null ? display.getDisplayId() : DEFAULT_DISPLAY);
+ display != null ? display.getDisplayId() : mDisplayTracker.getDefaultDisplayId());
}
private boolean onAccessibilityLongClick(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index dce69bb..8c19111 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -19,7 +19,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
-import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
@@ -55,6 +54,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
@@ -87,6 +87,7 @@
private final NavigationBarComponent.Factory mNavigationBarComponentFactory;
private FeatureFlags mFeatureFlags;
private final SecureSettings mSecureSettings;
+ private final DisplayTracker mDisplayTracker;
private final DisplayManager mDisplayManager;
private final TaskbarDelegate mTaskbarDelegate;
private int mNavMode;
@@ -119,12 +120,14 @@
Optional<Pip> pipOptional,
Optional<BackAnimation> backAnimation,
FeatureFlags featureFlags,
- SecureSettings secureSettings) {
+ SecureSettings secureSettings,
+ DisplayTracker displayTracker) {
mContext = context;
mHandler = mainHandler;
mNavigationBarComponentFactory = navigationBarComponentFactory;
mFeatureFlags = featureFlags;
mSecureSettings = secureSettings;
+ mDisplayTracker = displayTracker;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
commandQueue.addCallback(this);
configurationController.addCallback(this);
@@ -296,9 +299,10 @@
// Don't need to create nav bar on the default display if we initialize TaskBar.
final boolean shouldCreateDefaultNavbar = includeDefaultDisplay
&& !initializeTaskbarIfNecessary();
- Display[] displays = mDisplayManager.getDisplays();
+ Display[] displays = mDisplayTracker.getAllDisplays();
for (Display display : displays) {
- if (shouldCreateDefaultNavbar || display.getDisplayId() != DEFAULT_DISPLAY) {
+ if (shouldCreateDefaultNavbar
+ || display.getDisplayId() != mDisplayTracker.getDefaultDisplayId()) {
createNavigationBar(display, null /* savedState */, result);
}
}
@@ -317,7 +321,7 @@
}
final int displayId = display.getDisplayId();
- final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
+ final boolean isOnDefaultDisplay = displayId == mDisplayTracker.getDefaultDisplayId();
// We may show TaskBar on the default display for large screen device. Don't need to create
// navigation bar for this case.
@@ -412,7 +416,7 @@
/** @return {@link NavigationBarView} on the default display. */
public @Nullable NavigationBarView getDefaultNavigationBarView() {
- return getNavigationBarView(DEFAULT_DISPLAY);
+ return getNavigationBarView(mDisplayTracker.getDefaultDisplayId());
}
/**
@@ -433,7 +437,8 @@
final NavigationBarView navBarView = getNavigationBarView(displayId);
if (navBarView != null) {
navBarView.showPinningEnterExitToast(entering);
- } else if (displayId == DEFAULT_DISPLAY && mTaskbarDelegate.isInitialized()) {
+ } else if (displayId == mDisplayTracker.getDefaultDisplayId()
+ && mTaskbarDelegate.isInitialized()) {
mTaskbarDelegate.showPinningEnterExitToast(entering);
}
}
@@ -442,7 +447,8 @@
final NavigationBarView navBarView = getNavigationBarView(displayId);
if (navBarView != null) {
navBarView.showPinningEscapeToast();
- } else if (displayId == DEFAULT_DISPLAY && mTaskbarDelegate.isInitialized()) {
+ } else if (displayId == mDisplayTracker.getDefaultDisplayId()
+ && mTaskbarDelegate.isInitialized()) {
mTaskbarDelegate.showPinningEscapeToast();
}
}
@@ -459,7 +465,7 @@
/** @return {@link NavigationBar} on the default display. */
@Nullable
public NavigationBar getDefaultNavigationBar() {
- return mNavigationBars.get(DEFAULT_DISPLAY);
+ return mNavigationBars.get(mDisplayTracker.getDefaultDisplayId());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index 6793f01..a4de9ff 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -24,7 +24,6 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.SparseArray;
-import android.view.Display;
import android.view.IWallpaperVisibilityListener;
import android.view.IWindowManager;
import android.view.View;
@@ -32,6 +31,7 @@
import com.android.systemui.R;
import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.phone.BarTransitions;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
@@ -65,6 +65,7 @@
@org.jetbrains.annotations.NotNull
private final IWindowManager mWindowManagerService;
private final LightBarTransitionsController mLightTransitionsController;
+ private final DisplayTracker mDisplayTracker;
private final boolean mAllowAutoDimWallpaperNotVisible;
private boolean mWallpaperVisible;
@@ -89,18 +90,20 @@
public NavigationBarTransitions(
NavigationBarView view,
IWindowManager windowManagerService,
- LightBarTransitionsController.Factory lightBarTransitionsControllerFactory) {
+ LightBarTransitionsController.Factory lightBarTransitionsControllerFactory,
+ DisplayTracker displayTracker) {
super(view, R.drawable.nav_background);
mView = view;
mWindowManagerService = windowManagerService;
mLightTransitionsController = lightBarTransitionsControllerFactory.create(this);
+ mDisplayTracker = displayTracker;
mAllowAutoDimWallpaperNotVisible = view.getContext().getResources()
.getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
mDarkIntensityListeners = new ArrayList();
try {
mWallpaperVisible = mWindowManagerService.registerWallpaperVisibilityListener(
- mWallpaperVisibilityListener, Display.DEFAULT_DISPLAY);
+ mWallpaperVisibilityListener, mDisplayTracker.getDefaultDisplayId());
} catch (RemoteException e) {
}
mView.addOnLayoutChangeListener(
@@ -126,7 +129,7 @@
public void destroy() {
try {
mWindowManagerService.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener,
- Display.DEFAULT_DISPLAY);
+ mDisplayTracker.getDefaultDisplayId());
} catch (RemoteException e) {
}
mLightTransitionsController.destroy();
@@ -135,7 +138,10 @@
@Override
public void setAutoDim(boolean autoDim) {
// Ensure we aren't in gestural nav if we are triggering auto dim
- if (autoDim && isGesturalModeOnDefaultDisplay(mView.getContext(), mNavBarMode)) return;
+ if (autoDim && isGesturalModeOnDefaultDisplay(mView.getContext(), mDisplayTracker,
+ mNavBarMode)) {
+ return;
+ }
if (mAutoDim == autoDim) return;
mAutoDim = autoDim;
applyLightsOut(true, false);
@@ -219,7 +225,7 @@
@Override
public int getTintAnimationDuration() {
- if (isGesturalModeOnDefaultDisplay(mView.getContext(), mNavBarMode)) {
+ if (isGesturalModeOnDefaultDisplay(mView.getContext(), mDisplayTracker, mNavBarMode)) {
return Math.max(DEFAULT_COLOR_ADAPT_TRANSITION_TIME, MIN_COLOR_ADAPT_TRANSITION_TIME);
}
return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 88c4fd5..1a3be8e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -16,13 +16,11 @@
package com.android.systemui.navigationbar;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.inputmethodservice.InputMethodService.canImeRenderGesturalNavButtons;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
@@ -75,13 +73,12 @@
import com.android.systemui.navigationbar.buttons.RotationContextButton;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton.RotationButtonUpdatesCallback;
import com.android.systemui.shared.rotation.RotationButtonController;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
@@ -127,6 +124,7 @@
private int mDarkIconColor;
private EdgeBackGestureHandler mEdgeBackGestureHandler;
+ private DisplayTracker mDisplayTracker;
private final DeadZone mDeadZone;
private NavigationBarTransitions mBarTransitions;
@Nullable
@@ -361,6 +359,10 @@
mBgExecutor = bgExecutor;
}
+ public void setDisplayTracker(DisplayTracker displayTracker) {
+ mDisplayTracker = displayTracker;
+ }
+
public void setTouchHandler(Gefingerpoken touchHandler) {
mTouchHandler = touchHandler;
}
@@ -558,7 +560,8 @@
}
public void setBehavior(@Behavior int behavior) {
- mRotationButtonController.onBehaviorChanged(Display.DEFAULT_DISPLAY, behavior);
+ mRotationButtonController.onBehaviorChanged(mDisplayTracker.getDefaultDisplayId(),
+ behavior);
}
@Override
@@ -678,7 +681,7 @@
@VisibleForTesting
boolean isRecentsButtonDisabled() {
return mUseCarModeUi || !isOverviewEnabled()
- || getContext().getDisplayId() != Display.DEFAULT_DISPLAY;
+ || getContext().getDisplayId() != mDisplayTracker.getDefaultDisplayId();
}
private Display getContextDisplay() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 1230708..590efbb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -16,8 +16,6 @@
package com.android.systemui.navigationbar.gestural;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE;
import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
@@ -56,6 +54,7 @@
import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.NavigationEdgeBackPlugin;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.statusbar.VibratorHelper;
@@ -289,7 +288,8 @@
Context context,
LatencyTracker latencyTracker,
VibratorHelper vibratorHelper,
- @Background Executor backgroundExecutor) {
+ @Background Executor backgroundExecutor,
+ DisplayTracker displayTracker) {
super(context);
mWindowManager = context.getSystemService(WindowManager.class);
@@ -365,7 +365,7 @@
setVisibility(GONE);
- boolean isPrimaryDisplay = mContext.getDisplayId() == DEFAULT_DISPLAY;
+ boolean isPrimaryDisplay = mContext.getDisplayId() == displayTracker.getDefaultDisplayId();
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 08d1857..6bfe1a0 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -17,10 +17,12 @@
package com.android.systemui.notetask
import android.app.KeyguardManager
+import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.os.UserManager
+import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.util.kotlin.getOrNull
@@ -57,7 +59,7 @@
* If the keyguard is locked, notes will open as a full screen experience. A locked device has
* no contextual information which let us use the whole screen space available.
*
- * If no in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
+ * If not in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
* collapsed if the notes bubble is already opened.
*
* That will let users open other apps in full screen, and take contextual notes.
@@ -68,16 +70,23 @@
val bubbles = optionalBubbles.getOrNull() ?: return
val keyguardManager = optionalKeyguardManager.getOrNull() ?: return
val userManager = optionalUserManager.getOrNull() ?: return
- val intent = intentResolver.resolveIntent() ?: return
// TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
if (!userManager.isUserUnlocked) return
- if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
- context.startActivity(intent)
- } else {
- // TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter.
- bubbles.showOrHideAppBubble(intent)
+ val intent = intentResolver.resolveIntent() ?: return
+
+ // TODO(b/266686199): We should handle when app not available. For now, we log.
+ try {
+ if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
+ context.startActivity(intent)
+ } else {
+ bubbles.showOrHideAppBubble(intent)
+ }
+ } catch (e: ActivityNotFoundException) {
+ val message =
+ "Activity not found for action: ${NoteTaskIntentResolver.ACTION_CREATE_NOTE}."
+ Log.e(TAG, message, e)
}
}
@@ -106,6 +115,8 @@
}
companion object {
+ private val TAG = NoteTaskController::class.simpleName.orEmpty()
+
// TODO(b/254604589): Use final KeyEvent.KEYCODE_* instead.
const val NOTE_TASK_KEY_EVENT = 311
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
index 4b10d69..11dc1d7 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskIntentResolver.kt
@@ -16,70 +16,39 @@
package com.android.systemui.notetask
-import android.content.ComponentName
+import android.app.role.RoleManager
+import android.content.Context
import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.content.pm.PackageManager
-import android.content.pm.PackageManager.ResolveInfoFlags
-import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
import javax.inject.Inject
-/**
- * Class responsible to query all apps and find one that can handle the [ACTION_CREATE_NOTE]. If
- * found, an [Intent] ready for be launched will be returned. Otherwise, returns null.
- *
- * TODO(b/248274123): should be revisited once the notes role is implemented.
- */
internal class NoteTaskIntentResolver
@Inject
constructor(
- private val packageManager: PackageManager,
+ private val context: Context,
+ private val roleManager: RoleManager,
) {
fun resolveIntent(): Intent? {
- val intent = Intent(ACTION_CREATE_NOTE)
- val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
- val infoList = packageManager.queryIntentActivities(intent, flags)
+ val packageName = roleManager.getRoleHoldersAsUser(ROLE_NOTES, context.user).firstOrNull()
- for (info in infoList) {
- val packageName = info.activityInfo.applicationInfo.packageName ?: continue
- val activityName = resolveActivityNameForNotesAction(packageName) ?: continue
+ if (packageName.isNullOrEmpty()) return null
- return Intent(ACTION_CREATE_NOTE)
- .setPackage(packageName)
- .setComponent(ComponentName(packageName, activityName))
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- }
-
- return null
- }
-
- private fun resolveActivityNameForNotesAction(packageName: String): String? {
- val intent = Intent(ACTION_CREATE_NOTE).setPackage(packageName)
- val flags = ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
- val resolveInfo = packageManager.resolveActivity(intent, flags)
-
- val activityInfo = resolveInfo?.activityInfo ?: return null
- if (activityInfo.name.isNullOrBlank()) return null
- if (!activityInfo.exported) return null
- if (!activityInfo.enabled) return null
- if (!activityInfo.showWhenLocked) return null
- if (!activityInfo.turnScreenOn) return null
-
- return activityInfo.name
+ return Intent(ACTION_CREATE_NOTE)
+ .setPackage(packageName)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ // EXTRA_USE_STYLUS_MODE does not mean a stylus is in-use, but a stylus entrypoint was
+ // used to start it.
+ .putExtra(INTENT_EXTRA_USE_STYLUS_MODE, true)
}
companion object {
- // TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
+ // TODO(b/265912743): Use Intent.ACTION_CREATE_NOTE instead.
const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
// TODO(b/265912743): Use RoleManager.NOTES_ROLE instead.
- const val NOTE_ROLE = "android.app.role.NOTES"
+ const val ROLE_NOTES = "android.app.role.NOTES"
+
+ // TODO(b/265912743): Use Intent.INTENT_EXTRA_USE_STYLUS_MODE instead.
+ const val INTENT_EXTRA_USE_STYLUS_MODE = "android.intent.extra.USE_STYLUS_MODE"
}
}
-
-private val ActivityInfo.showWhenLocked: Boolean
- get() = flags and ActivityInfo.FLAG_SHOW_WHEN_LOCKED != 0
-
-private val ActivityInfo.turnScreenOn: Boolean
- get() = flags and ActivityInfo.FLAG_TURN_SCREEN_ON != 0
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index 22ce121..ec6a16a 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -51,7 +51,7 @@
featureFlags: FeatureFlags,
roleManager: RoleManager,
): Boolean {
- val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.NOTE_ROLE)
+ val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.ROLE_NOTES)
val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS)
return isRoleAvailable && isFeatureEnabled
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 2a6ca1a..8ad2f86 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -17,11 +17,11 @@
import android.content.Context
import android.util.AttributeSet
import android.view.ViewGroup
-import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import com.android.settingslib.Utils
import com.android.systemui.R
+import com.android.systemui.animation.LaunchableFrameLayout
import com.android.systemui.statusbar.events.BackgroundAnimatableView
class OngoingPrivacyChip @JvmOverloads constructor(
@@ -29,7 +29,7 @@
attrs: AttributeSet? = null,
defStyleAttrs: Int = 0,
defStyleRes: Int = 0
-) : FrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView {
+) : LaunchableFrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView {
private var iconMargin = 0
private var iconSize = 0
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 100853c..98af9df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -314,7 +314,6 @@
if (!TILES_SETTING.equals(key)) {
return;
}
- Log.d(TAG, "Recreating tiles");
if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) {
newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
}
@@ -327,6 +326,7 @@
}
}
if (tileSpecs.equals(mTileSpecs) && currentUser == mCurrentUser) return;
+ Log.d(TAG, "Recreating tiles: " + tileSpecs);
mTiles.entrySet().stream().filter(tile -> !tileSpecs.contains(tile.getKey())).forEach(
tile -> {
Log.d(TAG, "Destroying tile: " + tile.getKey());
@@ -372,6 +372,8 @@
Log.d(TAG, "Destroying not available tile: " + tileSpec);
mQSLogger.logTileDestroyed(tileSpec, "Tile not available");
}
+ } else {
+ Log.d(TAG, "No factory for a spec: " + tileSpec);
}
} catch (Throwable t) {
Log.w(TAG, "Error creating tile for spec: " + tileSpec, t);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index cfda9fd..7c2536d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.qs.external;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
import android.app.PendingIntent;
@@ -63,6 +62,7 @@
import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.settings.DisplayTracker;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -90,6 +90,7 @@
private final TileServiceManager mServiceManager;
private final int mUser;
private final CustomTileStatePersister mCustomTileStatePersister;
+ private final DisplayTracker mDisplayTracker;
@Nullable
private android.graphics.drawable.Icon mDefaultIcon;
@Nullable
@@ -120,7 +121,8 @@
String action,
Context userContext,
CustomTileStatePersister customTileStatePersister,
- TileServices tileServices
+ TileServices tileServices,
+ DisplayTracker displayTracker
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
@@ -135,6 +137,7 @@
mServiceManager = tileServices.getTileWrapper(this);
mService = mServiceManager.getTileService();
mCustomTileStatePersister = customTileStatePersister;
+ mDisplayTracker = displayTracker;
}
@Override
@@ -310,7 +313,7 @@
mIsShowingDialog = false;
try {
if (DEBUG) Log.d(TAG, "Removing token");
- mWindowManager.removeWindowToken(mToken, DEFAULT_DISPLAY);
+ mWindowManager.removeWindowToken(mToken, mDisplayTracker.getDefaultDisplayId());
} catch (RemoteException e) {
}
}
@@ -335,7 +338,8 @@
if (mIsTokenGranted && !mIsShowingDialog) {
try {
if (DEBUG) Log.d(TAG, "Removing token");
- mWindowManager.removeWindowToken(mToken, DEFAULT_DISPLAY);
+ mWindowManager.removeWindowToken(mToken,
+ mDisplayTracker.getDefaultDisplayId());
} catch (RemoteException e) {
}
mIsTokenGranted = false;
@@ -354,7 +358,7 @@
if (mIsTokenGranted) {
try {
if (DEBUG) Log.d(TAG, "Removing token");
- mWindowManager.removeWindowToken(mToken, DEFAULT_DISPLAY);
+ mWindowManager.removeWindowToken(mToken, mDisplayTracker.getDefaultDisplayId());
} catch (RemoteException e) {
}
}
@@ -398,8 +402,8 @@
mViewClicked = view;
try {
if (DEBUG) Log.d(TAG, "Adding token");
- mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG, DEFAULT_DISPLAY,
- null /* options */);
+ mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG,
+ mDisplayTracker.getDefaultDisplayId(), null /* options */);
mIsTokenGranted = true;
} catch (RemoteException e) {
}
@@ -566,6 +570,7 @@
final QSLogger mQSLogger;
final CustomTileStatePersister mCustomTileStatePersister;
private TileServices mTileServices;
+ final DisplayTracker mDisplayTracker;
Context mUserContext;
String mSpec = "";
@@ -581,7 +586,8 @@
ActivityStarter activityStarter,
QSLogger qsLogger,
CustomTileStatePersister customTileStatePersister,
- TileServices tileServices
+ TileServices tileServices,
+ DisplayTracker displayTracker
) {
mQSHostLazy = hostLazy;
mBackgroundLooper = backgroundLooper;
@@ -593,6 +599,7 @@
mQSLogger = qsLogger;
mCustomTileStatePersister = customTileStatePersister;
mTileServices = tileServices;
+ mDisplayTracker = displayTracker;
}
Builder setSpec(@NonNull String spec) {
@@ -623,7 +630,8 @@
action,
mUserContext,
mCustomTileStatePersister,
- mTileServices
+ mTileServices,
+ mDisplayTracker
);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1151475..a979e5a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
@@ -30,6 +29,7 @@
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
@@ -88,6 +88,7 @@
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.navigationbar.buttons.KeyButtonView;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -144,6 +145,7 @@
private final UserTracker mUserTracker;
private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController;
private final UiEventLogger mUiEventLogger;
+ private final DisplayTracker mDisplayTracker;
private Region mActiveNavBarRegion;
private SurfaceControl mNavigationBarSurface;
@@ -225,11 +227,11 @@
@Override
public void onImeSwitcherPressed() {
- // TODO(b/204901476) We're intentionally using DEFAULT_DISPLAY for now since
+ // TODO(b/204901476) We're intentionally using the default display for now since
// Launcher/Taskbar isn't display aware.
mContext.getSystemService(InputMethodManager.class)
.showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
- DEFAULT_DISPLAY);
+ mDisplayTracker.getDefaultDisplayId());
mUiEventLogger.log(KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_TAP);
}
@@ -507,6 +509,7 @@
UserTracker userTracker,
ScreenLifecycle screenLifecycle,
UiEventLogger uiEventLogger,
+ DisplayTracker displayTracker,
KeyguardUnlockAnimationController sysuiUnlockAnimationController,
AssistUtils assistUtils,
DumpManager dumpManager) {
@@ -534,6 +537,7 @@
mSysUiState = sysUiState;
mSysUiState.addCallback(this::notifySystemUiStateFlags);
mUiEventLogger = uiEventLogger;
+ mDisplayTracker = displayTracker;
dumpManager.registerDumpable(getClass().getSimpleName(), this);
@@ -652,13 +656,14 @@
}
private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
- boolean bouncerShowing, boolean isDozing, boolean panelExpanded) {
+ boolean bouncerShowing, boolean isDozing, boolean panelExpanded, boolean isDreaming) {
mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
keyguardShowing && !keyguardOccluded)
.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
keyguardShowing && keyguardOccluded)
.setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing)
.setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing)
+ .setFlag(SYSUI_STATE_DEVICE_DREAMING, isDreaming)
.commitUpdate(mContext.getDisplayId());
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index 01e32b7a..aa8e2c0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -22,7 +22,6 @@
import android.os.RemoteException
import android.os.UserHandle
import android.util.Log
-import android.view.Display
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationRunner
import android.view.RemoteAnimationAdapter
@@ -33,6 +32,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.DisplayTracker
import javax.inject.Inject
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineDispatcher
@@ -47,6 +47,7 @@
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
private val context: Context,
+ private val displayTracker: DisplayTracker
) {
/**
* Execute the given intent with startActivity while performing operations for screenshot action
@@ -82,7 +83,7 @@
val runner = RemoteAnimationAdapter(SCREENSHOT_REMOTE_RUNNER, 0, 0)
try {
WindowManagerGlobal.getWindowManagerService()
- .overridePendingAppTransitionRemote(runner, Display.DEFAULT_DISPLAY)
+ .overridePendingAppTransitionRemote(runner, displayTracker.defaultDisplayId)
} catch (e: Exception) {
Log.e(TAG, "Error overriding screenshot app transition", e)
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
index 814b8e9..4f5cb72 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
@@ -16,8 +16,6 @@
package com.android.systemui.screenshot;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.systemui.screenshot.ScreenshotController.ACTION_TYPE_EDIT;
import static com.android.systemui.screenshot.ScreenshotController.ACTION_TYPE_SHARE;
import static com.android.systemui.screenshot.ScreenshotController.EXTRA_ACTION_INTENT;
@@ -35,6 +33,7 @@
import android.view.RemoteAnimationAdapter;
import android.view.WindowManagerGlobal;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -52,14 +51,17 @@
private final CentralSurfaces mCentralSurfaces;
private final ActivityManagerWrapper mActivityManagerWrapper;
private final ScreenshotSmartActions mScreenshotSmartActions;
+ private final DisplayTracker mDisplayTracker;
@Inject
public ActionProxyReceiver(Optional<CentralSurfaces> centralSurfacesOptional,
ActivityManagerWrapper activityManagerWrapper,
- ScreenshotSmartActions screenshotSmartActions) {
+ ScreenshotSmartActions screenshotSmartActions,
+ DisplayTracker displayTracker) {
mCentralSurfaces = centralSurfacesOptional.orElse(null);
mActivityManagerWrapper = activityManagerWrapper;
mScreenshotSmartActions = screenshotSmartActions;
+ mDisplayTracker = displayTracker;
}
@Override
@@ -78,7 +80,8 @@
ScreenshotController.SCREENSHOT_REMOTE_RUNNER, 0, 0);
try {
WindowManagerGlobal.getWindowManagerService()
- .overridePendingAppTransitionRemote(runner, DEFAULT_DISPLAY);
+ .overridePendingAppTransitionRemote(runner,
+ mDisplayTracker.getDefaultDisplayId());
} catch (Exception e) {
Log.e(TAG, "Error overriding screenshot app transition", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
new file mode 100644
index 0000000..1e531ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MessageContainerController.kt
@@ -0,0 +1,113 @@
+package com.android.systemui.screenshot
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.graphics.drawable.Drawable
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewGroup.MarginLayoutParams
+import android.view.ViewTreeObserver
+import android.view.animation.AccelerateDecelerateInterpolator
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.constraintlayout.widget.Guideline
+import com.android.systemui.R
+
+/**
+ * MessageContainerController controls the display of content in the screenshot message container.
+ */
+class MessageContainerController
+constructor(
+ parent: ViewGroup,
+) {
+ private val guideline: Guideline = parent.requireViewById(R.id.guideline)
+ private val messageContainer: ViewGroup =
+ parent.requireViewById(R.id.screenshot_message_container)
+
+ /**
+ * Show a notification under the screenshot view indicating that a work profile screenshot has
+ * been taken and which app can be used to view it.
+ *
+ * @param appName The name of the app to use to view screenshots
+ * @param appIcon Optional icon for the relevant files app
+ * @param onDismiss Runnable to be run when the user dismisses this message
+ */
+ fun showWorkProfileMessage(appName: CharSequence, appIcon: Drawable?, onDismiss: Runnable) {
+ // Eventually this container will support multiple notification types, but for now just make
+ // sure we don't double inflate.
+ if (messageContainer.childCount == 0) {
+ View.inflate(
+ messageContainer.context,
+ R.layout.screenshot_work_profile_first_run,
+ messageContainer
+ )
+ }
+ if (appIcon != null) {
+ // Replace the default icon if one is provided.
+ val imageView: ImageView =
+ messageContainer.requireViewById<ImageView>(R.id.screenshot_message_icon)
+ imageView.setImageDrawable(appIcon)
+ }
+ val messageContent =
+ messageContainer.requireViewById<TextView>(R.id.screenshot_message_content)
+ messageContent.text =
+ messageContainer.context.getString(
+ R.string.screenshot_work_profile_notification,
+ appName
+ )
+ messageContainer.requireViewById<View>(R.id.message_dismiss_button).setOnClickListener {
+ animateOutMessageContainer()
+ onDismiss.run()
+ }
+
+ // Need the container to be fully measured before animating in (to know animation offset
+ // destination)
+ messageContainer.viewTreeObserver.addOnPreDrawListener(
+ object : ViewTreeObserver.OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ messageContainer.viewTreeObserver.removeOnPreDrawListener(this)
+ animateInMessageContainer()
+ return false
+ }
+ }
+ )
+ }
+
+ private fun animateInMessageContainer() {
+ if (messageContainer.visibility == View.VISIBLE) return
+
+ messageContainer.visibility = View.VISIBLE
+ getAnimator(true).start()
+ }
+
+ private fun animateOutMessageContainer() {
+ getAnimator(false).apply {
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ super.onAnimationEnd(animation)
+ messageContainer.visibility = View.INVISIBLE
+ }
+ }
+ )
+ start()
+ }
+ }
+
+ private fun getAnimator(animateIn: Boolean): Animator {
+ val params = messageContainer.layoutParams as MarginLayoutParams
+ val offset = messageContainer.height + params.topMargin + params.bottomMargin
+ val anim = if (animateIn) ValueAnimator.ofFloat(0f, 1f) else ValueAnimator.ofFloat(1f, 0f)
+ with(anim) {
+ duration = ScreenshotView.SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS
+ interpolator = AccelerateDecelerateInterpolator()
+ addUpdateListener { valueAnimator: ValueAnimator ->
+ val interpolation = valueAnimator.animatedValue as Float
+ guideline.setGuidelineEnd((interpolation * offset).toInt())
+ messageContainer.alpha = interpolation
+ }
+ }
+ return anim
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index adff6e1..ab13962 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -17,7 +17,6 @@
package com.android.systemui.screenshot;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY;
@@ -102,6 +101,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.util.Assert;
import com.google.common.util.concurrent.ListenableFuture;
@@ -273,6 +273,7 @@
private final ScrollCaptureClient mScrollCaptureClient;
private final PhoneWindow mWindow;
private final DisplayManager mDisplayManager;
+ private final DisplayTracker mDisplayTracker;
private final ScrollCaptureController mScrollCaptureController;
private final LongScreenshotData mLongScreenshotHolder;
private final boolean mIsLowRamDevice;
@@ -292,6 +293,7 @@
};
private ScreenshotView mScreenshotView;
+ private MessageContainerController mMessageContainerController;
private Bitmap mScreenBitmap;
private SaveImageInBackgroundTask mSaveInBgTask;
private boolean mScreenshotTakenInPortrait;
@@ -331,7 +333,8 @@
ActionIntentExecutor actionExecutor,
UserManager userManager,
WorkProfileMessageController workProfileMessageController,
- AssistContentRequester assistContentRequester
+ AssistContentRequester assistContentRequester,
+ DisplayTracker displayTracker
) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsController;
@@ -357,6 +360,7 @@
});
mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
+ mDisplayTracker = displayTracker;
final Context displayContext = context.createDisplayContext(getDefaultDisplay());
mContext = (WindowContext) displayContext.createWindowContext(TYPE_SCREENSHOT, null);
mWindowManager = mContext.getSystemService(WindowManager.class);
@@ -400,7 +404,8 @@
mCurrentRequestCallback = requestCallback;
if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN) {
Rect bounds = getFullScreenRect();
- screenshot.setBitmap(mImageCapture.captureDisplay(DEFAULT_DISPLAY, bounds));
+ screenshot.setBitmap(
+ mImageCapture.captureDisplay(mDisplayTracker.getDefaultDisplayId(), bounds));
screenshot.setScreenBounds(bounds);
}
@@ -627,6 +632,7 @@
// Inflate the screenshot layout
mScreenshotView = (ScreenshotView)
LayoutInflater.from(mContext).inflate(R.layout.screenshot, null);
+ mMessageContainerController = new MessageContainerController(mScreenshotView);
mScreenshotView.addOnAttachStateChangeListener(
new View.OnAttachStateChangeListener() {
@Override
@@ -667,6 +673,7 @@
setWindowFocusable(false);
}
}, mActionExecutor, mFlags);
+ mScreenshotView.setDefaultDisplay(mDisplayTracker.getDefaultDisplayId());
mScreenshotView.setDefaultTimeoutMillis(mScreenshotHandler.getDefaultTimeoutMillis());
mScreenshotView.setOnKeyListener((v, keyCode, event) -> {
@@ -700,7 +707,8 @@
// copy the input Rect, since SurfaceControl.screenshot can mutate it
Rect screenRect = new Rect(crop);
- Bitmap screenshot = mImageCapture.captureDisplay(DEFAULT_DISPLAY, crop);
+ Bitmap screenshot = mImageCapture.captureDisplay(mDisplayTracker.getDefaultDisplayId(),
+ crop);
if (screenshot == null) {
Log.e(TAG, "takeScreenshotInternal: Screenshot bitmap was null");
@@ -856,7 +864,7 @@
mLastScrollCaptureRequest.cancel(true);
}
final ListenableFuture<ScrollCaptureResponse> future =
- mScrollCaptureClient.request(DEFAULT_DISPLAY);
+ mScrollCaptureClient.request(mDisplayTracker.getDefaultDisplayId());
mLastScrollCaptureRequest = future;
mLastScrollCaptureRequest.addListener(() ->
onScrollCaptureResponseReady(future, owner), mMainExecutor);
@@ -887,7 +895,8 @@
mScreenshotView.showScrollChip(response.getPackageName(), /* onClick */ () -> {
DisplayMetrics displayMetrics = new DisplayMetrics();
getDefaultDisplay().getRealMetrics(displayMetrics);
- Bitmap newScreenshot = mImageCapture.captureDisplay(DEFAULT_DISPLAY,
+ Bitmap newScreenshot = mImageCapture.captureDisplay(
+ mDisplayTracker.getDefaultDisplayId(),
new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels));
mScreenshotView.prepareScrollingTransition(response, mScreenBitmap, newScreenshot,
@@ -951,7 +960,8 @@
SCREENSHOT_REMOTE_RUNNER, 0, 0);
try {
WindowManagerGlobal.getWindowManagerService()
- .overridePendingAppTransitionRemote(runner, DEFAULT_DISPLAY);
+ .overridePendingAppTransitionRemote(runner,
+ mDisplayTracker.getDefaultDisplayId());
} catch (Exception e) {
Log.e(TAG, "Error overriding screenshot app transition", e);
}
@@ -1185,7 +1195,8 @@
private void doPostAnimation(ScreenshotController.SavedImageData imageData) {
mScreenshotView.setChipIntents(imageData);
if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
- mWorkProfileMessageController.onScreenshotTaken(imageData.owner, mScreenshotView);
+ mWorkProfileMessageController.onScreenshotTaken(imageData.owner,
+ mMessageContainerController);
}
}
@@ -1289,7 +1300,7 @@
}
private Display getDefaultDisplay() {
- return mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+ return mDisplayManager.getDisplay(mDisplayTracker.getDefaultDisplayId());
}
private boolean allowLongScreenshots() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
index 3a35286..21a7310 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
@@ -32,12 +32,12 @@
import android.os.UserHandle
import android.os.UserManager
import android.util.Log
-import android.view.Display.DEFAULT_DISPLAY
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.infra.ServiceConnector
import com.android.systemui.SystemUIService
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.DisplayTracker
import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
import java.util.Arrays
import javax.inject.Inject
@@ -52,6 +52,7 @@
private val userMgr: UserManager,
private val atmService: IActivityTaskManager,
@Background val bgDispatcher: CoroutineDispatcher,
+ private val displayTracker: DisplayTracker
) : ScreenshotPolicy {
private val proxyConnector: ServiceConnector<IScreenshotProxy> =
@@ -64,7 +65,7 @@
)
override fun getDefaultDisplayId(): Int {
- return DEFAULT_DISPLAY
+ return displayTracker.defaultDisplayId
}
override suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index ce7f2e7..afba7ad 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -33,7 +33,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -82,7 +81,6 @@
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.TextView;
import androidx.constraintlayout.widget.ConstraintLayout;
@@ -102,8 +100,7 @@
* Handles the visual elements and animations for the screenshot flow.
*/
public class ScreenshotView extends FrameLayout implements
- ViewTreeObserver.OnComputeInternalInsetsListener,
- WorkProfileMessageController.WorkProfileMessageDisplay {
+ ViewTreeObserver.OnComputeInternalInsetsListener {
interface ScreenshotViewCallback {
void onUserInteraction();
@@ -123,7 +120,7 @@
private static final long SCREENSHOT_TO_CORNER_X_DURATION_MS = 234;
private static final long SCREENSHOT_TO_CORNER_Y_DURATION_MS = 500;
private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
- private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
+ public static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100;
private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
@@ -135,14 +132,13 @@
private final AccessibilityManager mAccessibilityManager;
private final GestureDetector mSwipeDetector;
+ private int mDefaultDisplay = Display.DEFAULT_DISPLAY;
private int mNavMode;
private boolean mOrientationPortrait;
private boolean mDirectionLTR;
private ImageView mScrollingScrim;
private DraggableConstraintLayout mScreenshotStatic;
- private ViewGroup mMessageContainer;
- private TextView mMessageContent;
private ImageView mScreenshotPreview;
private ImageView mScreenshotBadge;
private View mScreenshotPreviewBorder;
@@ -294,8 +290,11 @@
mDismissButton.getBoundsOnScreen(tmpRect);
swipeRegion.op(tmpRect, Region.Op.UNION);
- mMessageContainer.findViewById(R.id.message_dismiss_button).getBoundsOnScreen(tmpRect);
- swipeRegion.op(tmpRect, Region.Op.UNION);
+ View messageDismiss = findViewById(R.id.message_dismiss_button);
+ if (messageDismiss != null) {
+ messageDismiss.getBoundsOnScreen(tmpRect);
+ swipeRegion.op(tmpRect, Region.Op.UNION);
+ }
return swipeRegion;
}
@@ -326,7 +325,7 @@
private void startInputListening() {
stopInputListening();
- mInputMonitor = new InputMonitorCompat("Screenshot", Display.DEFAULT_DISPLAY);
+ mInputMonitor = new InputMonitorCompat("Screenshot", mDefaultDisplay);
mInputEventReceiver = mInputMonitor.getInputReceiver(
Looper.getMainLooper(), Choreographer.getInstance(), ev -> {
if (ev instanceof MotionEvent) {
@@ -351,39 +350,11 @@
}
}
- /**
- * Show a notification under the screenshot view indicating that a work profile screenshot has
- * been taken and which app can be used to view it.
- *
- * @param appName The name of the app to use to view screenshots
- * @param appIcon Optional icon for the relevant files app
- * @param onDismiss Runnable to be run when the user dismisses this message
- */
- @Override
- public void showWorkProfileMessage(CharSequence appName, @Nullable Drawable appIcon,
- Runnable onDismiss) {
- if (appIcon != null) {
- // Replace the default icon if one is provided.
- ImageView imageView = mMessageContainer.findViewById(R.id.screenshot_message_icon);
- imageView.setImageDrawable(appIcon);
- }
- mMessageContent.setText(
- mContext.getString(R.string.screenshot_work_profile_notification, appName));
- mMessageContainer.setVisibility(VISIBLE);
- mMessageContainer.findViewById(R.id.message_dismiss_button).setOnClickListener((v) -> {
- mMessageContainer.setVisibility(View.GONE);
- onDismiss.run();
- });
- }
-
@Override // View
protected void onFinishInflate() {
+ super.onFinishInflate();
mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim));
mScreenshotStatic = requireNonNull(findViewById(R.id.screenshot_static));
- mMessageContainer =
- requireNonNull(mScreenshotStatic.findViewById(R.id.screenshot_message_container));
- mMessageContent =
- requireNonNull(mMessageContainer.findViewById(R.id.screenshot_message_content));
mScreenshotPreview = requireNonNull(findViewById(R.id.screenshot_preview));
mScreenshotPreviewBorder = requireNonNull(
@@ -484,6 +455,10 @@
mPackageName = packageName;
}
+ void setDefaultDisplay(int displayId) {
+ mDefaultDisplay = displayId;
+ }
+
void updateInsets(WindowInsets insets) {
int orientation = mContext.getResources().getConfiguration().orientation;
mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
index 5d7e56f..b4a07d4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/WorkProfileMessageController.kt
@@ -40,10 +40,10 @@
) {
/**
- * Determine if a message should be shown to the user, send message details to messageDisplay if
- * appropriate.
+ * Determine if a message should be shown to the user, send message details to
+ * MessageContainerController if appropriate.
*/
- fun onScreenshotTaken(userHandle: UserHandle, messageDisplay: WorkProfileMessageDisplay) {
+ fun onScreenshotTaken(userHandle: UserHandle, messageContainer: MessageContainerController) {
if (userManager.isManagedProfile(userHandle.identifier) && !messageAlreadyDismissed()) {
var badgedIcon: Drawable? = null
var label: CharSequence? = null
@@ -65,7 +65,9 @@
val badgedLabel =
packageManager.getUserBadgedLabel(label ?: defaultFileAppName(), userHandle)
- messageDisplay.showWorkProfileMessage(badgedLabel, badgedIcon) { onMessageDismissed() }
+ messageContainer.showWorkProfileMessage(badgedLabel, badgedIcon) {
+ onMessageDismissed()
+ }
}
}
@@ -89,15 +91,6 @@
private fun defaultFileAppName() = context.getString(R.string.screenshot_default_files_app_name)
- /** UI that can show work profile messages (ScreenshotView in practice) */
- interface WorkProfileMessageDisplay {
- /**
- * Show the given message and icon, calling onDismiss if the user explicitly dismisses the
- * message.
- */
- fun showWorkProfileMessage(text: CharSequence, icon: Drawable?, onDismiss: Runnable)
- }
-
companion object {
const val TAG = "WorkProfileMessageCtrl"
const val SHARED_PREFERENCES_NAME = "com.android.systemui.screenshot"
diff --git a/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
new file mode 100644
index 0000000..bb7f721
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/DisplayTracker.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.settings
+
+import android.view.Display
+import java.util.concurrent.Executor
+
+/**
+ * Display tracker for SystemUI.
+ *
+ * This tracker provides async access to display information, as well as callbacks for display
+ * changes.
+ */
+interface DisplayTracker {
+
+ /** The id for the default display for the current SystemUI instance. */
+ val defaultDisplayId: Int
+
+ /** All displays that should be associated with the current SystemUI instance. */
+ val allDisplays: Array<Display>
+
+ /**
+ * Add a [Callback] to be notified of display changes, including additions, removals, and
+ * configuration changes, on a particular [Executor].
+ */
+ fun addDisplayChangeCallback(callback: Callback, executor: Executor)
+
+ /**
+ * Add a [Callback] to be notified of display brightness changes, on a particular [Executor].
+ * This callback will trigger Callback#onDisplayChanged for a display brightness change.
+ */
+ fun addBrightnessChangeCallback(callback: Callback, executor: Executor)
+
+ /** Remove a [Callback] previously added. */
+ fun removeCallback(callback: Callback)
+
+ /** Ćallback for notifying of changes. */
+ interface Callback {
+
+ /** Notifies that a display has been added. */
+ @JvmDefault fun onDisplayAdded(displayId: Int) {}
+
+ /** Notifies that a display has been removed. */
+ @JvmDefault fun onDisplayRemoved(displayId: Int) {}
+
+ /** Notifies a display has been changed */
+ @JvmDefault fun onDisplayChanged(displayId: Int) {}
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
new file mode 100644
index 0000000..5169f88
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.settings
+
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+import android.os.Handler
+import android.view.Display
+import androidx.annotation.GuardedBy
+import androidx.annotation.VisibleForTesting
+import androidx.annotation.WorkerThread
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.Assert
+import java.lang.ref.WeakReference
+import java.util.concurrent.Executor
+
+class DisplayTrackerImpl
+internal constructor(
+ val displayManager: DisplayManager,
+ @Background val backgroundHandler: Handler
+) : DisplayTracker {
+ override val defaultDisplayId: Int = Display.DEFAULT_DISPLAY
+ override val allDisplays: Array<Display>
+ get() = displayManager.displays
+
+ @GuardedBy("displayCallbacks")
+ private val displayCallbacks: MutableList<DisplayTrackerDataItem> = ArrayList()
+ @GuardedBy("brightnessCallbacks")
+ private val brightnessCallbacks: MutableList<DisplayTrackerDataItem> = ArrayList()
+
+ @VisibleForTesting
+ val displayChangedListener: DisplayManager.DisplayListener =
+ object : DisplayManager.DisplayListener {
+ override fun onDisplayAdded(displayId: Int) {
+ val list = synchronized(displayCallbacks) { displayCallbacks.toList() }
+ onDisplayAdded(displayId, list)
+ }
+
+ override fun onDisplayRemoved(displayId: Int) {
+ val list = synchronized(displayCallbacks) { displayCallbacks.toList() }
+ onDisplayRemoved(displayId, list)
+ }
+
+ override fun onDisplayChanged(displayId: Int) {
+ val list = synchronized(displayCallbacks) { displayCallbacks.toList() }
+ onDisplayChanged(displayId, list)
+ }
+ }
+
+ @VisibleForTesting
+ val displayBrightnessChangedListener: DisplayManager.DisplayListener =
+ object : DisplayManager.DisplayListener {
+ override fun onDisplayAdded(displayId: Int) {}
+
+ override fun onDisplayRemoved(displayId: Int) {}
+
+ override fun onDisplayChanged(displayId: Int) {
+ val list = synchronized(brightnessCallbacks) { brightnessCallbacks.toList() }
+ onDisplayChanged(displayId, list)
+ }
+ }
+
+ override fun addDisplayChangeCallback(callback: DisplayTracker.Callback, executor: Executor) {
+ synchronized(displayCallbacks) {
+ if (displayCallbacks.isEmpty()) {
+ displayManager.registerDisplayListener(displayChangedListener, backgroundHandler)
+ }
+ displayCallbacks.add(DisplayTrackerDataItem(WeakReference(callback), executor))
+ }
+ }
+
+ override fun addBrightnessChangeCallback(
+ callback: DisplayTracker.Callback,
+ executor: Executor
+ ) {
+ synchronized(brightnessCallbacks) {
+ if (brightnessCallbacks.isEmpty()) {
+ displayManager.registerDisplayListener(
+ displayBrightnessChangedListener,
+ backgroundHandler,
+ EVENT_FLAG_DISPLAY_BRIGHTNESS
+ )
+ }
+ brightnessCallbacks.add(DisplayTrackerDataItem(WeakReference(callback), executor))
+ }
+ }
+
+ override fun removeCallback(callback: DisplayTracker.Callback) {
+ synchronized(displayCallbacks) {
+ val changed = displayCallbacks.removeIf { it.sameOrEmpty(callback) }
+ if (changed && displayCallbacks.isEmpty()) {
+ displayManager.unregisterDisplayListener(displayChangedListener)
+ }
+ }
+
+ synchronized(brightnessCallbacks) {
+ val changed = brightnessCallbacks.removeIf { it.sameOrEmpty(callback) }
+ if (changed && brightnessCallbacks.isEmpty()) {
+ displayManager.unregisterDisplayListener(displayBrightnessChangedListener)
+ }
+ }
+ }
+
+ @WorkerThread
+ private fun onDisplayAdded(displayId: Int, list: List<DisplayTrackerDataItem>) {
+ Assert.isNotMainThread()
+
+ notifySubscribers({ onDisplayAdded(displayId) }, list)
+ }
+
+ @WorkerThread
+ private fun onDisplayRemoved(displayId: Int, list: List<DisplayTrackerDataItem>) {
+ Assert.isNotMainThread()
+
+ notifySubscribers({ onDisplayRemoved(displayId) }, list)
+ }
+
+ @WorkerThread
+ private fun onDisplayChanged(displayId: Int, list: List<DisplayTrackerDataItem>) {
+ Assert.isNotMainThread()
+
+ notifySubscribers({ onDisplayChanged(displayId) }, list)
+ }
+
+ private inline fun notifySubscribers(
+ crossinline action: DisplayTracker.Callback.() -> Unit,
+ list: List<DisplayTrackerDataItem>
+ ) {
+ list.forEach {
+ if (it.callback.get() != null) {
+ it.executor.execute { it.callback.get()?.action() }
+ }
+ }
+ }
+
+ private data class DisplayTrackerDataItem(
+ val callback: WeakReference<DisplayTracker.Callback>,
+ val executor: Executor
+ ) {
+ fun sameOrEmpty(other: DisplayTracker.Callback): Boolean {
+ return callback.get()?.equals(other) ?: true
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
index 1558ac5..287e810 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
@@ -62,12 +62,24 @@
fun removeCallback(callback: Callback)
/**
- * Ćallback for notifying of changes.
+ * Callback for notifying of changes.
*/
interface Callback {
/**
+ * Notifies that the current user is being changed.
+ * Override this method to run things while the screen is frozen for the user switch.
+ * Please use {@link #onUserChanged} if the task doesn't need to push the unfreezing of the
+ * screen further. Please be aware that code executed in this callback will lengthen the
+ * user switch duration.
+ */
+ @JvmDefault
+ fun onUserChanging(newUser: Int, userContext: Context) {}
+
+ /**
* Notifies that the current user has changed.
+ * Override this method to run things after the screen is unfrozen for the user switch.
+ * Please see {@link #onUserChanging} if you need to hide jank.
*/
@JvmDefault
fun onUserChanged(newUser: Int, userContext: Context) {}
@@ -78,4 +90,4 @@
@JvmDefault
fun onProfilesChanged(profiles: List<@JvmSuppressWildcards UserInfo>) {}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 61390c5..9f551c6 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -16,6 +16,8 @@
package com.android.systemui.settings
+import android.app.IActivityManager
+import android.app.UserSwitchObserver
import android.content.BroadcastReceiver
import android.content.ContentResolver
import android.content.Context
@@ -23,6 +25,7 @@
import android.content.IntentFilter
import android.content.pm.UserInfo
import android.os.Handler
+import android.os.IRemoteCallback
import android.os.UserHandle
import android.os.UserManager
import android.util.Log
@@ -34,6 +37,7 @@
import java.io.PrintWriter
import java.lang.IllegalStateException
import java.lang.ref.WeakReference
+import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executor
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@@ -56,6 +60,7 @@
class UserTrackerImpl internal constructor(
private val context: Context,
private val userManager: UserManager,
+ private val iActivityManager: IActivityManager,
private val dumpManager: DumpManager,
private val backgroundHandler: Handler
) : UserTracker, Dumpable, BroadcastReceiver() {
@@ -107,7 +112,6 @@
setUserIdInternal(startingUser)
val filter = IntentFilter().apply {
- addAction(Intent.ACTION_USER_SWITCHED)
addAction(Intent.ACTION_USER_INFO_CHANGED)
// These get called when a managed profile goes in or out of quiet mode.
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
@@ -118,14 +122,13 @@
}
context.registerReceiverForAllUsers(this, filter, null /* permission */, backgroundHandler)
+ registerUserSwitchObserver()
+
dumpManager.registerDumpable(TAG, this)
}
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
- Intent.ACTION_USER_SWITCHED -> {
- handleSwitchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL))
- }
Intent.ACTION_USER_INFO_CHANGED,
Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
@@ -157,22 +160,43 @@
return ctx to profiles
}
+ private fun registerUserSwitchObserver() {
+ iActivityManager.registerUserSwitchObserver(object : UserSwitchObserver() {
+ override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
+ backgroundHandler.run {
+ handleUserSwitching(newUserId)
+ reply?.sendResult(null)
+ }
+ }
+
+ override fun onUserSwitchComplete(newUserId: Int) {
+ backgroundHandler.run {
+ handleUserSwitchComplete(newUserId)
+ }
+ }
+ }, TAG)
+ }
+
@WorkerThread
- private fun handleSwitchUser(newUser: Int) {
+ private fun handleUserSwitching(newUserId: Int) {
Assert.isNotMainThread()
- if (newUser == UserHandle.USER_NULL) {
- Log.w(TAG, "handleSwitchUser - Couldn't get new id from intent")
- return
- }
+ Log.i(TAG, "Switching to user $newUserId")
- if (newUser == userId) return
- Log.i(TAG, "Switching to user $newUser")
-
- val (ctx, profiles) = setUserIdInternal(newUser)
-
+ setUserIdInternal(newUserId)
notifySubscribers {
- onUserChanged(newUser, ctx)
- onProfilesChanged(profiles)
+ onUserChanging(newUserId, userContext)
+ }.await()
+ }
+
+ @WorkerThread
+ private fun handleUserSwitchComplete(newUserId: Int) {
+ Assert.isNotMainThread()
+ Log.i(TAG, "Switched to user $newUserId")
+
+ setUserIdInternal(newUserId)
+ notifySubscribers {
+ onUserChanged(newUserId, userContext)
+ onProfilesChanged(userProfiles)
}
}
@@ -201,17 +225,25 @@
}
}
- private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) {
+ private inline fun notifySubscribers(
+ crossinline action: UserTracker.Callback.() -> Unit
+ ): CountDownLatch {
val list = synchronized(callbacks) {
callbacks.toList()
}
+ val latch = CountDownLatch(list.size)
+
list.forEach {
if (it.callback.get() != null) {
it.executor.execute {
it.callback.get()?.action()
+ latch.countDown()
}
+ } else {
+ latch.countDown()
}
}
+ return latch
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
@@ -258,4 +290,4 @@
fun sameOrEmpty(other: UserTracker.Callback): Boolean {
return callback.get()?.equals(other) ?: true
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 2f6081b..8089d01 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -27,10 +27,10 @@
import android.database.ContentObserver;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -49,6 +49,7 @@
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -78,19 +79,14 @@
private final ToggleSlider mControl;
private final DisplayManager mDisplayManager;
private final UserTracker mUserTracker;
+ private final DisplayTracker mDisplayTracker;
private final IVrManager mVrManager;
private final Executor mMainExecutor;
private final Handler mBackgroundHandler;
private final BrightnessObserver mBrightnessObserver;
- private final DisplayListener mDisplayListener = new DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) {}
-
- @Override
- public void onDisplayRemoved(int displayId) {}
-
+ private final DisplayTracker.Callback mBrightnessListener = new DisplayTracker.Callback() {
@Override
public void onDisplayChanged(int displayId) {
mBackgroundHandler.post(mUpdateSliderRunnable);
@@ -143,14 +139,14 @@
cr.registerContentObserver(
BRIGHTNESS_FOR_VR_FLOAT_URI,
false, this, UserHandle.USER_ALL);
- mDisplayManager.registerDisplayListener(mDisplayListener, mHandler,
- DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
+ mDisplayTracker.addBrightnessChangeCallback(mBrightnessListener,
+ new HandlerExecutor(mHandler));
}
public void stopObserving() {
final ContentResolver cr = mContext.getContentResolver();
cr.unregisterContentObserver(this);
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ mDisplayTracker.removeCallback(mBrightnessListener);
}
}
@@ -292,6 +288,7 @@
Context context,
ToggleSlider control,
UserTracker userTracker,
+ DisplayTracker displayTracker,
@Main Executor mainExecutor,
@Background Handler bgHandler) {
mContext = context;
@@ -300,6 +297,7 @@
mMainExecutor = mainExecutor;
mBackgroundHandler = bgHandler;
mUserTracker = userTracker;
+ mDisplayTracker = displayTracker;
mBrightnessObserver = new BrightnessObserver(mHandler);
mDisplayId = mContext.getDisplayId();
@@ -450,6 +448,7 @@
public static class Factory {
private final Context mContext;
private final UserTracker mUserTracker;
+ private final DisplayTracker mDisplayTracker;
private final Executor mMainExecutor;
private final Handler mBackgroundHandler;
@@ -457,10 +456,12 @@
public Factory(
Context context,
UserTracker userTracker,
+ DisplayTracker displayTracker,
@Main Executor mainExecutor,
@Background Handler bgHandler) {
mContext = context;
mUserTracker = userTracker;
+ mDisplayTracker = displayTracker;
mMainExecutor = mainExecutor;
mBackgroundHandler = bgHandler;
}
@@ -471,6 +472,7 @@
mContext,
toggleSlider,
mUserTracker,
+ mDisplayTracker,
mMainExecutor,
mBackgroundHandler);
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index e208be9..8879501 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -36,6 +36,7 @@
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import java.util.List;
@@ -49,16 +50,19 @@
private BrightnessController mBrightnessController;
private final BrightnessSliderController.Factory mToggleSliderFactory;
private final UserTracker mUserTracker;
+ private final DisplayTracker mDisplayTracker;
private final Executor mMainExecutor;
private final Handler mBackgroundHandler;
@Inject
public BrightnessDialog(
UserTracker userTracker,
+ DisplayTracker displayTracker,
BrightnessSliderController.Factory factory,
@Main Executor mainExecutor,
@Background Handler bgHandler) {
mUserTracker = userTracker;
+ mDisplayTracker = displayTracker;
mToggleSliderFactory = factory;
mMainExecutor = mainExecutor;
mBackgroundHandler = bgHandler;
@@ -106,7 +110,7 @@
frame.addView(controller.getRootView(), MATCH_PARENT, WRAP_CONTENT);
mBrightnessController = new BrightnessController(
- this, controller, mUserTracker, mMainExecutor, mBackgroundHandler);
+ this, controller, mUserTracker, mDisplayTracker, mMainExecutor, mBackgroundHandler);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/dagger/MultiUserUtilsModule.java b/packages/SystemUI/src/com/android/systemui/settings/dagger/MultiUserUtilsModule.java
index 2f62e44..e9a1dd7 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/dagger/MultiUserUtilsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/dagger/MultiUserUtilsModule.java
@@ -17,7 +17,9 @@
package com.android.systemui.settings.dagger;
import android.app.ActivityManager;
+import android.app.IActivityManager;
import android.content.Context;
+import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.UserManager;
@@ -25,6 +27,8 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.settings.DisplayTracker;
+import com.android.systemui.settings.DisplayTrackerImpl;
import com.android.systemui.settings.UserContentResolverProvider;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserFileManager;
@@ -57,15 +61,26 @@
static UserTracker provideUserTracker(
Context context,
UserManager userManager,
+ IActivityManager iActivityManager,
DumpManager dumpManager,
@Background Handler handler
) {
int startingUser = ActivityManager.getCurrentUser();
- UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, dumpManager, handler);
+ UserTrackerImpl tracker = new UserTrackerImpl(context, userManager, iActivityManager,
+ dumpManager, handler);
tracker.initialize(startingUser);
return tracker;
}
+ @SysUISingleton
+ @Provides
+ static DisplayTracker provideDisplayTracker(
+ DisplayManager displayManager,
+ @Background Handler handler
+ ) {
+ return new DisplayTrackerImpl(displayManager, handler);
+ }
+
@Binds
@IntoMap
@ClassKey(UserFileManagerImpl.class)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index cbb133b..197232e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade
+import android.animation.Animator
import android.annotation.IdRes
import android.app.StatusBarManager
import android.content.res.Configuration
@@ -175,9 +176,13 @@
var shadeExpandedFraction = -1f
set(value) {
if (field != value) {
+ val oldAlpha = header.alpha
header.alpha = ShadeInterpolation.getContentAlpha(value)
field = value
- updateVisibility()
+ if ((oldAlpha == 0f && header.alpha > 0f) ||
+ (oldAlpha > 0f && header.alpha == 0f)) {
+ updateVisibility()
+ }
}
}
@@ -336,9 +341,28 @@
.setUpdateListener {
updateVisibility()
}
+ .setListener(endAnimationListener)
.start()
}
+ private val endAnimationListener = object : Animator.AnimatorListener {
+ override fun onAnimationCancel(animation: Animator?) {
+ clearListeners()
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ clearListeners()
+ }
+
+ override fun onAnimationRepeat(animation: Animator?) {}
+
+ override fun onAnimationStart(animation: Animator?) {}
+
+ private fun clearListeners() {
+ header.animate().setListener(null).setUpdateListener(null)
+ }
+ }
+
private fun loadConstraints() {
if (header is MotionLayout) {
// Use resources.getXml instead of passing the resource id due to bug b/205018300
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 392a851..b6f08f8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -140,12 +140,16 @@
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
+import com.android.systemui.keyguard.ui.binder.KeyguardLongPressViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
@@ -204,7 +208,6 @@
import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
import com.android.systemui.statusbar.phone.KeyguardBottomAreaViewController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardClockPositionAlgorithm;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
@@ -243,6 +246,7 @@
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
import kotlinx.coroutines.CoroutineDispatcher;
@CentralSurfacesComponent.CentralSurfacesScope
@@ -698,6 +702,7 @@
private LockscreenToOccludedTransitionViewModel mLockscreenToOccludedTransitionViewModel;
private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final KeyguardInteractor mKeyguardInteractor;
private CoroutineDispatcher mMainDispatcher;
private boolean mIsOcclusionTransitionRunning = false;
private int mDreamingToLockscreenTransitionTranslationY;
@@ -827,7 +832,9 @@
LockscreenToOccludedTransitionViewModel lockscreenToOccludedTransitionViewModel,
@Main CoroutineDispatcher mainDispatcher,
KeyguardTransitionInteractor keyguardTransitionInteractor,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ KeyguardLongPressViewModel keyguardLongPressViewModel,
+ KeyguardInteractor keyguardInteractor) {
keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
public void onKeyguardFadingAwayChanged() {
@@ -848,6 +855,7 @@
mGoneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel;
mLockscreenToOccludedTransitionViewModel = lockscreenToOccludedTransitionViewModel;
mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+ mKeyguardInteractor = keyguardInteractor;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
@@ -1000,6 +1008,14 @@
updateUserSwitcherFlags();
mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
+ KeyguardLongPressViewBinder.bind(
+ mView.requireViewById(R.id.keyguard_long_press),
+ keyguardLongPressViewModel,
+ () -> {
+ onEmptySpaceClick();
+ return Unit.INSTANCE;
+ },
+ mFalsingManager);
onFinishInflate();
keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -2157,6 +2173,7 @@
}
ValueAnimator animator = createHeightAnimator(target, overshootAmount);
if (expand) {
+ maybeVibrateOnOpening(true /* openingWithTouch */);
if (expandBecauseOfFalsing && vel < 0) {
vel = 0;
}
@@ -2167,6 +2184,7 @@
animator.setDuration(SHADE_OPEN_SPRING_OUT_DURATION);
}
} else {
+ mHasVibratedOnOpen = false;
if (shouldUseDismissingAnimation()) {
if (vel == 0) {
animator.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED);
@@ -2516,7 +2534,7 @@
if (!mSplitShadeEnabled
&& computeQsExpansionFraction() <= 0.01 && getExpandedFraction() < 1.0) {
mShadeLog.logMotionEvent(event,
- "handleQsTouch: QQS touched while shade collapsing, QS tracking disabled");
+ "handleQsTouch: shade touched while collapsing, QS tracking disabled");
mQsTracking = false;
}
if (!mQsExpandImmediate && mQsTracking) {
@@ -3129,6 +3147,7 @@
mQsClipBottom,
radius,
qsVisible && !mSplitShadeEnabled);
+ mKeyguardInteractor.setQuickSettingsVisible(mQsVisible);
}
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusViewController.setClipBounds(clipStatusView ? mLastQsClipBounds : null);
@@ -3767,7 +3786,8 @@
// change due to "unlock hint animation." In this case, fading out the bottom area
// would also hide the message that says "swipe to unlock," we don't want to do that.
float expansionAlpha = MathUtils.map(
- isUnlockHintRunning() ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f, 0f, 1f,
+ isUnlockHintRunning() ? 0 : KeyguardBouncerConstants.ALPHA_EXPANSION_THRESHOLD, 1f,
+ 0f, 1f,
getExpandedFraction());
float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
alpha *= mBottomAreaShadeAlpha;
@@ -6375,7 +6395,7 @@
mShadeLog.logHasVibrated(mHasVibratedOnOpen, mExpandedFraction);
}
addMovement(event);
- if (!isFullyCollapsed()) {
+ if (!isFullyCollapsed() && !isOnKeyguard()) {
maybeVibrateOnOpening(true /* openingWithTouch */);
}
float h = y - mInitialExpandY;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index ab2e692..156e4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -563,7 +563,8 @@
mCurrentState.keyguardOccluded,
mCurrentState.bouncerShowing,
mCurrentState.dozing,
- mCurrentState.panelExpanded);
+ mCurrentState.panelExpanded,
+ mCurrentState.dreaming);
}
}
@@ -778,6 +779,12 @@
}
@Override
+ public void setDreaming(boolean dreaming) {
+ mCurrentState.dreaming = dreaming;
+ apply(mCurrentState);
+ }
+
+ @Override
public void setForcePluginOpen(boolean forceOpen, Object token) {
if (forceOpen) {
mCurrentState.forceOpenTokens.add(token);
@@ -904,5 +911,10 @@
public void onDozingChanged(boolean isDozing) {
setDozing(isDozing);
}
+
+ @Override
+ public void onDreamingChanged(boolean isDreaming) {
+ setDreaming(isDreaming);
+ }
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
index 736404aa..fed9b84 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowState.kt
@@ -23,8 +23,8 @@
import com.android.systemui.statusbar.StatusBarState
/**
- * Represents state of shade window, used by [NotificationShadeWindowControllerImpl].
- * Contains nested class [Buffer] for pretty table logging in bug reports.
+ * Represents state of shade window, used by [NotificationShadeWindowControllerImpl]. Contains
+ * nested class [Buffer] for pretty table logging in bug reports.
*/
class NotificationShadeWindowState(
@JvmField var keyguardShowing: Boolean = false,
@@ -55,6 +55,7 @@
@JvmField var remoteInputActive: Boolean = false,
@JvmField var forcePluginOpen: Boolean = false,
@JvmField var dozing: Boolean = false,
+ @JvmField var dreaming: Boolean = false,
@JvmField var scrimsVisibility: Int = 0,
@JvmField var backgroundBlurRadius: Int = 0,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index 85b259e..de02115 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -31,6 +31,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.fragments.FragmentService
import com.android.systemui.navigationbar.NavigationModeController
import com.android.systemui.plugins.qs.QS
import com.android.systemui.plugins.qs.QSContainerController
@@ -54,6 +55,7 @@
private val largeScreenShadeHeaderController: LargeScreenShadeHeaderController,
private val shadeExpansionStateManager: ShadeExpansionStateManager,
private val featureFlags: FeatureFlags,
+ private val fragmentService: FragmentService,
@Main private val delayableExecutor: DelayableExecutor
) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
@@ -128,6 +130,7 @@
mView.setInsetsChangedListener(delayedInsetSetter)
mView.setQSFragmentAttachedListener { qs: QS -> qs.setContainerController(this) }
mView.setConfigurationChangedListener { updateResources() }
+ fragmentService.getFragmentHostManager(mView).addTagListener(QS.TAG, mView)
}
override fun onViewDetached() {
@@ -136,6 +139,7 @@
mView.removeOnInsetsChangedListener()
mView.removeQSFragmentAttachedListener()
mView.setConfigurationChangedListener(null)
+ fragmentService.getFragmentHostManager(mView).removeTagListener(QS.TAG, mView)
}
fun updateResources() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
index 02316b7..f73dde6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQuickSettingsContainer.java
@@ -29,7 +29,6 @@
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.systemui.R;
-import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.statusbar.notification.AboveShelfObserver;
@@ -133,18 +132,6 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- FragmentHostManager.get(this).addTagListener(QS.TAG, this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- FragmentHostManager.get(this).removeTagListener(QS.TAG, this);
- }
-
- @Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mInsetsChangedListener.accept(insets);
return insets;
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
index b02a45a..393279b 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
@@ -18,7 +18,6 @@
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.smartspace.SmartspacePrecondition
import com.android.systemui.smartspace.SmartspaceTargetFilter
-import com.android.systemui.smartspace.filters.LockscreenAndDreamTargetFilter
import com.android.systemui.smartspace.preconditions.LockscreenPrecondition
import dagger.Binds
import dagger.BindsOptionalOf
@@ -35,11 +34,6 @@
const val DREAM_SMARTSPACE_DATA_PLUGIN = "dreams_smartspace_data_plugin"
/**
- * The lockscreen smartspace target filter.
- */
- const val LOCKSCREEN_SMARTSPACE_TARGET_FILTER = "lockscreen_smartspace_target_filter"
-
- /**
* The dream smartspace target filter.
*/
const val DREAM_SMARTSPACE_TARGET_FILTER = "dream_smartspace_target_filter"
@@ -48,6 +42,11 @@
* The precondition for dream smartspace
*/
const val DREAM_SMARTSPACE_PRECONDITION = "dream_smartspace_precondition"
+
+ /**
+ * The BcSmartspaceDataPlugin for the standalone weather.
+ */
+ const val WEATHER_SMARTSPACE_DATA_PLUGIN = "weather_smartspace_data_plugin"
}
@BindsOptionalOf
@@ -59,12 +58,6 @@
abstract fun optionalDreamsBcSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
@Binds
- @Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
- abstract fun provideLockscreenSmartspaceTargetFilter(
- filter: LockscreenAndDreamTargetFilter?
- ): SmartspaceTargetFilter?
-
- @Binds
@Named(DREAM_SMARTSPACE_PRECONDITION)
abstract fun bindSmartspacePrecondition(
lockscreenPrecondition: LockscreenPrecondition?
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedButton.java
index 87c12c2..6577cf6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedButton.java
@@ -20,10 +20,21 @@
import android.util.AttributeSet;
import android.widget.Button;
+import com.android.systemui.animation.LaunchableView;
+import com.android.systemui.animation.LaunchableViewDelegate;
+
+import kotlin.Unit;
+
/**
* A Button which doesn't have overlapping drawing commands
*/
-public class AlphaOptimizedButton extends Button {
+public class AlphaOptimizedButton extends Button implements LaunchableView {
+ private LaunchableViewDelegate mDelegate = new LaunchableViewDelegate(this,
+ (visibility) -> {
+ super.setVisibility(visibility);
+ return Unit.INSTANCE;
+ });
+
public AlphaOptimizedButton(Context context) {
super(context);
}
@@ -45,4 +56,14 @@
public boolean hasOverlappingRendering() {
return false;
}
+
+ @Override
+ public void setShouldBlockVisibilityChanges(boolean block) {
+ mDelegate.setShouldBlockVisibilityChanges(block);
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ mDelegate.setVisibility(visibility);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 1758379..f2e729d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -20,7 +20,6 @@
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
@@ -38,7 +37,6 @@
import android.hardware.biometrics.IBiometricContextListener;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
-import android.hardware.display.DisplayManager;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.inputmethodservice.InputMethodService.BackDispositionMode;
import android.media.INearbyMediaDevicesProvider;
@@ -46,6 +44,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
@@ -60,6 +59,7 @@
import android.view.WindowInsetsController.Behavior;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IAddTileResultCallback;
@@ -70,6 +70,7 @@
import com.android.internal.util.GcUtils;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.dump.DumpHandler;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -89,8 +90,7 @@
* are coalesced, note that they are all idempotent.
*/
public class CommandQueue extends IStatusBar.Stub implements
- CallbackController<Callbacks>,
- DisplayManager.DisplayListener {
+ CallbackController<Callbacks> {
private static final String TAG = CommandQueue.class.getSimpleName();
private static final int INDEX_MASK = 0xffff;
@@ -192,6 +192,7 @@
private ProtoTracer mProtoTracer;
private final @Nullable CommandRegistry mRegistry;
private final @Nullable DumpHandler mDumpHandler;
+ private final @Nullable DisplayTracker mDisplayTracker;
/**
* These methods are called back on the main thread.
@@ -351,7 +352,7 @@
}
/**
- * @see DisplayManager.DisplayListener#onDisplayRemoved(int)
+ * @see DisplayTracker.Callback#onDisplayRemoved(int)
*/
default void onDisplayRemoved(int displayId) {
}
@@ -500,12 +501,14 @@
default void showMediaOutputSwitcher(String packageName) {}
}
- public CommandQueue(Context context) {
- this(context, null, null, null);
+ @VisibleForTesting
+ public CommandQueue(Context context, DisplayTracker displayTracker) {
+ this(context, displayTracker, null, null, null);
}
public CommandQueue(
Context context,
+ DisplayTracker displayTracker,
ProtoTracer protoTracer,
CommandRegistry registry,
DumpHandler dumpHandler
@@ -513,33 +516,28 @@
mProtoTracer = protoTracer;
mRegistry = registry;
mDumpHandler = dumpHandler;
- context.getSystemService(DisplayManager.class).registerDisplayListener(this, mHandler);
+ mDisplayTracker = displayTracker;
+ mDisplayTracker.addDisplayChangeCallback(new DisplayTracker.Callback() {
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ synchronized (mLock) {
+ mDisplayDisabled.remove(displayId);
+ }
+ // This callback is registered with {@link #mHandler} that already posts to run
+ // on main thread, so it is safe to dispatch directly.
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ mCallbacks.get(i).onDisplayRemoved(displayId);
+ }
+ }
+ }, new HandlerExecutor(mHandler));
// We always have default display.
- setDisabled(DEFAULT_DISPLAY, DISABLE_NONE, DISABLE2_NONE);
+ setDisabled(mDisplayTracker.getDefaultDisplayId(), DISABLE_NONE, DISABLE2_NONE);
}
- @Override
- public void onDisplayAdded(int displayId) { }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- synchronized (mLock) {
- mDisplayDisabled.remove(displayId);
- }
- // This callback is registered with {@link #mHandler} that already posts to run on main
- // thread, so it is safe to dispatch directly.
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- mCallbacks.get(i).onDisplayRemoved(displayId);
- }
- }
-
- @Override
- public void onDisplayChanged(int displayId) { }
-
// TODO(b/118592525): add multi-display support if needed.
public boolean panelsEnabled() {
- final int disabled1 = getDisabled1(DEFAULT_DISPLAY);
- final int disabled2 = getDisabled2(DEFAULT_DISPLAY);
+ final int disabled1 = getDisabled1(mDisplayTracker.getDefaultDisplayId());
+ final int disabled2 = getDisabled2(mDisplayTracker.getDefaultDisplayId());
return (disabled1 & StatusBarManager.DISABLE_EXPAND) == 0
&& (disabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 63179da..5adb58b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -77,6 +77,12 @@
*/
public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
view.animate().cancel();
+
+ // Don't fade out if already not visible.
+ if (view.getAlpha() == 0.0f) {
+ return;
+ }
+
if (fadeOutAmount == 1.0f && view.getVisibility() != View.GONE) {
view.setVisibility(View.INVISIBLE);
} else if (view.getVisibility() == View.INVISIBLE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 006b552..6481855 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -43,6 +43,7 @@
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
import static com.android.systemui.plugins.log.LogLevel.ERROR;
+import android.app.AlarmManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -98,6 +99,7 @@
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.AlarmTimeout;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
@@ -127,10 +129,8 @@
private static final String TAG = "KeyguardIndication";
private static final boolean DEBUG_CHARGING_SPEED = false;
- private static final int MSG_HIDE_TRANSIENT = 1;
- private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
- private static final int MSG_HIDE_BIOMETRIC_MESSAGE = 3;
- private static final int MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON = 4;
+ private static final int MSG_SHOW_ACTION_TO_UNLOCK = 1;
+ private static final int MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON = 2;
private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
public static final long DEFAULT_HIDE_DELAY_MS =
3500 + KeyguardIndicationTextView.Y_IN_DURATION;
@@ -212,6 +212,11 @@
};
private boolean mFaceLockedOutThisAuthSession;
+ // Use AlarmTimeouts to guarantee that the events are handled even if scheduled and
+ // triggered while the device is asleep
+ private final AlarmTimeout mHideTransientMessageHandler;
+ private final AlarmTimeout mHideBiometricMessageHandler;
+
/**
* Creates a new KeyguardIndicationController and registers callbacks.
*/
@@ -238,7 +243,9 @@
AccessibilityManager accessibilityManager,
FaceHelpMessageDeferral faceHelpMessageDeferral,
KeyguardLogger keyguardLogger,
- AlternateBouncerInteractor alternateBouncerInteractor) {
+ AlternateBouncerInteractor alternateBouncerInteractor,
+ AlarmManager alarmManager
+ ) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mDevicePolicyManager = devicePolicyManager;
@@ -273,17 +280,26 @@
mHandler = new Handler(mainLooper) {
@Override
public void handleMessage(Message msg) {
- if (msg.what == MSG_HIDE_TRANSIENT) {
- hideTransientIndication();
- } else if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) {
+ if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) {
showActionToUnlock();
- } else if (msg.what == MSG_HIDE_BIOMETRIC_MESSAGE) {
- hideBiometricMessage();
} else if (msg.what == MSG_RESET_ERROR_MESSAGE_ON_SCREEN_ON) {
mBiometricErrorMessageToShowOnScreenOn = null;
}
}
};
+
+ mHideTransientMessageHandler = new AlarmTimeout(
+ alarmManager,
+ this::hideTransientIndication,
+ TAG,
+ mHandler
+ );
+ mHideBiometricMessageHandler = new AlarmTimeout(
+ alarmManager,
+ this::hideBiometricMessage,
+ TAG,
+ mHandler
+ );
}
/** Call this after construction to finish setting up the instance. */
@@ -335,6 +351,8 @@
*/
public void destroy() {
mHandler.removeCallbacksAndMessages(null);
+ mHideBiometricMessageHandler.cancel();
+ mHideTransientMessageHandler.cancel();
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
}
@@ -679,7 +697,7 @@
if (visible) {
// If this is called after an error message was already shown, we should not clear it.
// Otherwise the error message won't be shown
- if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
+ if (!mHideTransientMessageHandler.isScheduled()) {
hideTransientIndication();
}
updateDeviceEntryIndication(false);
@@ -727,16 +745,14 @@
* Hides transient indication in {@param delayMs}.
*/
public void hideTransientIndicationDelayed(long delayMs) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
+ mHideTransientMessageHandler.schedule(delayMs, AlarmTimeout.MODE_RESCHEDULE_IF_SCHEDULED);
}
/**
* Hides biometric indication in {@param delayMs}.
*/
public void hideBiometricMessageDelayed(long delayMs) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_HIDE_BIOMETRIC_MESSAGE), delayMs);
+ mHideBiometricMessageHandler.schedule(delayMs, AlarmTimeout.MODE_RESCHEDULE_IF_SCHEDULED);
}
/**
@@ -751,7 +767,6 @@
*/
private void showTransientIndication(CharSequence transientIndication) {
mTransientIndication = transientIndication;
- mHandler.removeMessages(MSG_HIDE_TRANSIENT);
hideTransientIndicationDelayed(DEFAULT_HIDE_DELAY_MS);
updateTransient();
@@ -777,7 +792,6 @@
mBiometricMessageFollowUp = biometricMessageFollowUp;
mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
- mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
hideBiometricMessageDelayed(
mBiometricMessageFollowUp != null
? IMPORTANT_MSG_MIN_DURATION * 2
@@ -791,7 +805,7 @@
if (mBiometricMessage != null || mBiometricMessageFollowUp != null) {
mBiometricMessage = null;
mBiometricMessageFollowUp = null;
- mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
+ mHideBiometricMessageHandler.cancel();
updateBiometricMessage();
}
}
@@ -802,7 +816,7 @@
public void hideTransientIndication() {
if (mTransientIndication != null) {
mTransientIndication = null;
- mHandler.removeMessages(MSG_HIDE_TRANSIENT);
+ mHideTransientMessageHandler.cancel();
updateTransient();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index 0b1807d..2ca0b00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -143,6 +143,9 @@
/** Sets the state of whether sysui is dozing or not. */
default void setDozing(boolean dozing) {}
+ /** Sets the state of whether sysui is dreaming or not. */
+ default void setDreaming(boolean dreaming) {}
+
/** Sets the state of whether plugin open is forced or not. */
default void setForcePluginOpen(boolean forcePluginOpen, Object token) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 186e6dc..784e2d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -129,6 +129,11 @@
private boolean mIsDozing;
/**
+ * If the device is currently dreaming or not.
+ */
+ private boolean mIsDreaming;
+
+ /**
* If the status bar is currently expanded or not.
*/
private boolean mIsExpanded;
@@ -294,6 +299,29 @@
}
@Override
+ public boolean setIsDreaming(boolean isDreaming) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "setIsDreaming:" + isDreaming);
+ }
+ if (mIsDreaming == isDreaming) {
+ return false;
+ }
+
+ mIsDreaming = isDreaming;
+
+ synchronized (mListeners) {
+ String tag = getClass().getSimpleName() + "#setIsDreaming";
+ DejankUtils.startDetectingBlockingIpcs(tag);
+ for (RankedListener rl : new ArrayList<>(mListeners)) {
+ rl.mListener.onDreamingChanged(isDreaming);
+ }
+ DejankUtils.stopDetectingBlockingIpcs(tag);
+ }
+
+ return true;
+ }
+
+ @Override
public void setAndInstrumentDozeAmount(View view, float dozeAmount, boolean animated) {
if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
if (animated && mDozeAmountTarget == dozeAmount) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
index e0cf812..088c568 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -99,6 +99,13 @@
boolean setIsDozing(boolean isDozing);
/**
+ * Update the dreaming state from {@link CentralSurfaces}'s perspective
+ * @param isDreaming whether we are dreaming
+ * @return {@code true} if the state changed, else {@code false}
+ */
+ boolean setIsDreaming(boolean isDreaming);
+
+ /**
* Changes the current doze amount, also starts the
* {@link com.android.internal.jank.InteractionJankMonitor InteractionJankMonitor} as possible.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 098c617..d7568a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -39,6 +39,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.carrier.QSCarrierGroupController;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.MediaArtworkProcessor;
@@ -184,11 +185,12 @@
@SysUISingleton
static CommandQueue provideCommandQueue(
Context context,
+ DisplayTracker displayTracker,
ProtoTracer protoTracer,
CommandRegistry registry,
DumpHandler dumpHandler
) {
- return new CommandQueue(context, protoTracer, registry, dumpHandler);
+ return new CommandQueue(context, displayTracker, protoTracer, registry, dumpHandler);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt
index 3a4731a..92a8356 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt
@@ -20,9 +20,9 @@
import android.annotation.CallSuper
import android.os.Looper
import android.view.Choreographer
-import android.view.Display
import android.view.InputEvent
import android.view.MotionEvent
+import com.android.systemui.settings.DisplayTracker
import com.android.systemui.shared.system.InputChannelCompat
import com.android.systemui.shared.system.InputMonitorCompat
@@ -38,7 +38,8 @@
* gesture is detected, they should call [onGestureDetected] (which will notify the callbacks).
*/
abstract class GenericGestureDetector(
- private val tag: String
+ private val tag: String,
+ private val displayTracker: DisplayTracker
) {
/**
* Active callbacks, each associated with a tag. Gestures will only be monitored if
@@ -86,7 +87,7 @@
internal open fun startGestureListening() {
stopGestureListening()
- inputMonitor = InputMonitorCompat(tag, Display.DEFAULT_DISPLAY).also {
+ inputMonitor = InputMonitorCompat(tag, displayTracker.defaultDisplayId).also {
inputReceiver = it.getInputReceiver(
Looper.getMainLooper(),
Choreographer.getInstance(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
index 5ab3d7c..693ae66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.view.MotionEvent
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.settings.DisplayTracker
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
@@ -28,9 +29,10 @@
@Inject
constructor(
context: Context,
+ displayTracker: DisplayTracker,
logger: SwipeUpGestureLogger,
private val statusBarWindowController: StatusBarWindowController,
-) : SwipeUpGestureHandler(context, logger, loggerTag = LOGGER_TAG) {
+) : SwipeUpGestureHandler(context, displayTracker, logger, loggerTag = LOGGER_TAG) {
override fun startOfGestureIsWithinBounds(ev: MotionEvent): Boolean {
// Gesture starts just below the status bar
return ev.y >= statusBarWindowController.statusBarHeight &&
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
index 5ecc35c..452762d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeUpGestureHandler.kt
@@ -24,6 +24,7 @@
import android.view.MotionEvent.ACTION_MOVE
import android.view.MotionEvent.ACTION_UP
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.settings.DisplayTracker
/**
* A class to detect a generic "swipe up" gesture. To be notified when the swipe up gesture is
@@ -32,9 +33,10 @@
@SysUISingleton
abstract class SwipeUpGestureHandler(
context: Context,
+ displayTracker: DisplayTracker,
private val logger: SwipeUpGestureLogger,
- private val loggerTag: String,
-) : GenericGestureDetector(SwipeUpGestureHandler::class.simpleName!!) {
+ private val loggerTag: String
+) : GenericGestureDetector(SwipeUpGestureHandler::class.simpleName!!, displayTracker) {
private var startY: Float = 0f
private var startTime: Long = 0L
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
index 7ffb07a..a901d597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
@@ -21,6 +21,7 @@
import android.view.InputEvent
import android.view.MotionEvent
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.settings.DisplayTracker
import javax.inject.Inject
/**
@@ -29,8 +30,9 @@
*/
@SysUISingleton
class TapGestureDetector @Inject constructor(
- private val context: Context
-) : GenericGestureDetector(TapGestureDetector::class.simpleName!!) {
+ private val context: Context,
+ displayTracker: DisplayTracker
+) : GenericGestureDetector(TapGestureDetector::class.simpleName!!, displayTracker) {
private val gestureListener = object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 665b1bc..f4ca9cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -52,6 +52,7 @@
import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.shared.regionsampling.UpdateColorCallback
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.WEATHER_SMARTSPACE_DATA_PLUGIN
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -60,6 +61,7 @@
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
+import javax.inject.Named
/** Controller for managing the smartspace view on the lockscreen */
@SysUISingleton
@@ -82,6 +84,8 @@
@Main private val uiExecutor: Executor,
@Background private val bgExecutor: Executor,
@Main private val handler: Handler,
+ @Named(WEATHER_SMARTSPACE_DATA_PLUGIN)
+ optionalWeatherPlugin: Optional<BcSmartspaceDataPlugin>,
optionalPlugin: Optional<BcSmartspaceDataPlugin>,
optionalConfigPlugin: Optional<BcSmartspaceConfigPlugin>,
) {
@@ -90,6 +94,7 @@
}
private var session: SmartspaceSession? = null
+ private val weatherPlugin: BcSmartspaceDataPlugin? = optionalWeatherPlugin.orElse(null)
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null)
@@ -131,6 +136,10 @@
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
execution.assertIsMainThread()
+
+ // The weather data plugin takes unfiltered targets and performs the filtering internally.
+ weatherPlugin?.onTargetsAvailable(targets)
+
val filteredTargets = targets.filter(::filterSmartspaceTarget)
plugin?.onTargetsAvailable(filteredTargets)
if (!isContentUpdatedOnce) {
@@ -209,12 +218,38 @@
return plugin != null
}
+ fun isDateWeatherDecoupled(): Boolean {
+ execution.assertIsMainThread()
+
+ return featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED) &&
+ weatherPlugin != null
+ }
+
private fun updateBypassEnabled() {
val bypassEnabled = bypassController.bypassEnabled
smartspaceViews.forEach { it.setKeyguardBypassEnabled(bypassEnabled) }
}
/**
+ * Constructs the weather view and connects it to the smartspace service.
+ */
+ fun buildAndConnectWeatherView(parent: ViewGroup): View? {
+ execution.assertIsMainThread()
+
+ if (!isEnabled()) {
+ throw RuntimeException("Cannot build view when not enabled")
+ }
+ if (!isDateWeatherDecoupled()) {
+ throw RuntimeException("Cannot build weather view when not decoupled")
+ }
+
+ val view = buildView(parent, weatherPlugin)
+ connectSession()
+
+ return view
+ }
+
+ /**
* Constructs the smartspace view and connects it to the smartspace service.
*/
fun buildAndConnectView(parent: ViewGroup): View? {
@@ -224,17 +259,17 @@
throw RuntimeException("Cannot build view when not enabled")
}
- val view = buildView(parent)
+ val view = buildView(parent, plugin, configPlugin)
connectSession()
return view
}
- fun requestSmartspaceUpdate() {
- session?.requestSmartspaceUpdate()
- }
-
- private fun buildView(parent: ViewGroup): View? {
+ private fun buildView(
+ parent: ViewGroup,
+ plugin: BcSmartspaceDataPlugin?,
+ configPlugin: BcSmartspaceConfigPlugin? = null
+ ): View? {
if (plugin == null) {
return null
}
@@ -242,7 +277,7 @@
val ssView = plugin.getView(parent)
ssView.setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
ssView.registerDataProvider(plugin)
- ssView.registerConfigProvider(configPlugin)
+ configPlugin?.let { ssView.registerConfigProvider(it) }
ssView.setIntentStarter(object : BcSmartspaceDataPlugin.IntentStarter {
override fun startIntent(view: View, intent: Intent, showOnLockscreen: Boolean) {
@@ -273,7 +308,8 @@
}
private fun connectSession() {
- if (plugin == null || session != null || smartspaceViews.isEmpty()) {
+ if (weatherPlugin == null && plugin == null) return
+ if (session != null || smartspaceViews.isEmpty()) {
return
}
@@ -310,15 +346,21 @@
statusBarStateController.addCallback(statusBarStateListener)
bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener)
- plugin.registerSmartspaceEventNotifier {
- e -> session?.notifySmartspaceEvent(e)
- }
+ weatherPlugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
+ plugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
updateBypassEnabled()
reloadSmartspace()
}
/**
+ * Requests the smartspace session for an update.
+ */
+ fun requestSmartspaceUpdate() {
+ session?.requestSmartspaceUpdate()
+ }
+
+ /**
* Disconnects the smartspace view from the smartspace service and cleans up any resources.
*/
fun disconnect() {
@@ -341,9 +383,13 @@
bypassController.unregisterOnBypassStateChangedListener(bypassStateChangedListener)
session = null
+ weatherPlugin?.registerSmartspaceEventNotifier(null)
+ weatherPlugin?.onTargetsAvailable(emptyList())
+
plugin?.registerSmartspaceEventNotifier(null)
plugin?.onTargetsAvailable(emptyList())
- Log.d(TAG, "Ending smartspace session for lockscreen")
+
+ Log.d(TAG, "Ended smartspace session for lockscreen")
}
fun addListener(listener: SmartspaceTargetListener) {
@@ -357,8 +403,11 @@
}
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
+ if (isDateWeatherDecoupled()) {
+ return t.featureType != SmartspaceTarget.FEATURE_WEATHER
+ }
if (!showNotifications) {
- return t.getFeatureType() == SmartspaceTarget.FEATURE_WEATHER
+ return t.featureType == SmartspaceTarget.FEATURE_WEATHER
}
return when (t.userHandle) {
userTracker.userHandle -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 808638a..8436ff7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -16,27 +16,15 @@
package com.android.systemui.statusbar.notification.dagger;
-import android.app.INotificationManager;
import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.content.pm.ShortcutManager;
-import android.os.Handler;
-import android.view.accessibility.AccessibilityManager;
-import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.UserContextProvider;
-import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeEventsModule;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
@@ -50,7 +38,6 @@
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
-import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.provider.NotificationVisibilityProviderImpl;
import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderModule;
import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
@@ -72,22 +59,17 @@
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
-import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.wmshell.BubblesManager;
-import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Provider;
import dagger.Binds;
-import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -109,48 +91,6 @@
@Binds
StackScrollAlgorithm.BypassController bindBypassController(KeyguardBypassController impl);
- /** Provides an instance of {@link NotificationGutsManager} */
- @SysUISingleton
- @Provides
- static NotificationGutsManager provideNotificationGutsManager(
- Context context,
- Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
- @Main Handler mainHandler,
- @Background Handler bgHandler,
- AccessibilityManager accessibilityManager,
- HighPriorityProvider highPriorityProvider,
- INotificationManager notificationManager,
- PeopleSpaceWidgetManager peopleSpaceWidgetManager,
- LauncherApps launcherApps,
- ShortcutManager shortcutManager,
- ChannelEditorDialogController channelEditorDialogController,
- UserContextProvider contextTracker,
- AssistantFeedbackController assistantFeedbackController,
- Optional<BubblesManager> bubblesManagerOptional,
- UiEventLogger uiEventLogger,
- OnUserInteractionCallback onUserInteractionCallback,
- ShadeController shadeController) {
- return new NotificationGutsManager(
- context,
- centralSurfacesOptionalLazy,
- mainHandler,
- bgHandler,
- accessibilityManager,
- highPriorityProvider,
- notificationManager,
- peopleSpaceWidgetManager,
- launcherApps,
- shortcutManager,
- channelEditorDialogController,
- contextTracker,
- assistantFeedbackController,
- bubblesManagerOptional,
- uiEventLogger,
- onUserInteractionCallback,
- shadeController
- );
- }
-
/** Provides an instance of {@link NotifGutsViewManager} */
@Binds
NotifGutsViewManager bindNotifGutsViewManager(NotificationGutsManager notificationGutsManager);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index ea12b82..37ff11d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -44,12 +44,10 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.notification.ConversationIconFactory;
-import com.android.systemui.Dependency;
-import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -65,28 +63,29 @@
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewListener;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
-import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.wmshell.BubblesManager;
-import java.io.PrintWriter;
import java.util.Optional;
+import javax.inject.Inject;
+
import dagger.Lazy;
/**
* Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
* closing guts, and keeping track of the currently exposed notification guts.
*/
+@SysUISingleton
public class NotificationGutsManager implements NotifGutsViewManager {
private static final String TAG = "NotificationGutsManager";
// Must match constant in Settings. Used to highlight preferences when linking to Settings.
private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
- private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ private final MetricsLogger mMetricsLogger;
private final Context mContext;
private final AccessibilityManager mAccessibilityManager;
private final HighPriorityProvider mHighPriorityProvider;
@@ -94,12 +93,9 @@
private final OnUserInteractionCallback mOnUserInteractionCallback;
// Dependencies:
- private final NotificationLockscreenUserManager mLockscreenUserManager =
- Dependency.get(NotificationLockscreenUserManager.class);
- private final StatusBarStateController mStatusBarStateController =
- Dependency.get(StatusBarStateController.class);
- private final DeviceProvisionedController mDeviceProvisionedController =
- Dependency.get(DeviceProvisionedController.class);
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+ private final StatusBarStateController mStatusBarStateController;
+ private final DeviceProvisionedController mDeviceProvisionedController;
private final AssistantFeedbackController mAssistantFeedbackController;
// which notification is currently being longpress-examined by the user
@@ -124,9 +120,7 @@
private final ShadeController mShadeController;
private NotifGutsViewListener mGutsListener;
- /**
- * Injected constructor. See {@link NotificationsModule}.
- */
+ @Inject
public NotificationGutsManager(Context context,
Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
@Main Handler mainHandler,
@@ -143,7 +137,11 @@
Optional<BubblesManager> bubblesManagerOptional,
UiEventLogger uiEventLogger,
OnUserInteractionCallback onUserInteractionCallback,
- ShadeController shadeController) {
+ ShadeController shadeController,
+ NotificationLockscreenUserManager notificationLockscreenUserManager,
+ StatusBarStateController statusBarStateController,
+ DeviceProvisionedController deviceProvisionedController,
+ MetricsLogger metricsLogger) {
mContext = context;
mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
mMainHandler = mainHandler;
@@ -161,6 +159,10 @@
mUiEventLogger = uiEventLogger;
mOnUserInteractionCallback = onUserInteractionCallback;
mShadeController = shadeController;
+ mLockscreenUserManager = notificationLockscreenUserManager;
+ mStatusBarStateController = statusBarStateController;
+ mDeviceProvisionedController = deviceProvisionedController;
+ mMetricsLogger = metricsLogger;
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -372,7 +374,8 @@
mDeviceProvisionedController.isDeviceProvisioned(),
row.getIsNonblockable(),
mHighPriorityProvider.isHighPriority(row.getEntry()),
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index ea0060a..8a50f2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -204,10 +204,11 @@
boolean isDeviceProvisioned,
boolean isNonblockable,
boolean wasShownHighPriority,
- AssistantFeedbackController assistantFeedbackController)
+ AssistantFeedbackController assistantFeedbackController,
+ MetricsLogger metricsLogger)
throws RemoteException {
mINotificationManager = iNotificationManager;
- mMetricsLogger = Dependency.get(MetricsLogger.class);
+ mMetricsLogger = metricsLogger;
mOnUserInteractionCallback = onUserInteractionCallback;
mChannelEditorDialogController = channelEditorDialogController;
mAssistantFeedbackController = assistantFeedbackController;
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 dd75d35..85399ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1306,8 +1306,13 @@
// Set up the quick settings tile panel
final View container = mNotificationShadeWindowView.findViewById(R.id.qs_frame);
if (container != null) {
- FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
- ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
+ FragmentHostManager fragmentHostManager =
+ mFragmentService.getFragmentHostManager(container);
+ ExtensionFragmentListener.attachExtensonToFragment(
+ mFragmentService,
+ container,
+ QS.TAG,
+ R.id.qs_frame,
mExtensionController
.newExtension(QS.class)
.withPlugin(QS.class)
@@ -1408,12 +1413,14 @@
// to dismiss the lock screen until entering the SIM PIN.
// - QS is expanded and we're swiping - swiping up now will hide QS, not dismiss the
// keyguard.
+ // - Shade is in QQS over keyguard - swiping up should take us back to keyguard
if (!isKeyguardShowing()
|| mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()
|| isOccluded()
|| !mKeyguardStateController.canDismissLockScreen()
|| mKeyguardViewMediator.isAnySimPinSecure()
- || (mNotificationPanelViewController.isQsExpanded() && trackingTouch)) {
+ || (mNotificationPanelViewController.isQsExpanded() && trackingTouch)
+ || mNotificationPanelViewController.getBarState() == StatusBarState.SHADE_LOCKED) {
return;
}
@@ -1476,7 +1483,9 @@
}
protected QS createDefaultQSFragment() {
- return FragmentHostManager.get(mNotificationShadeWindowView).create(QSFragment.class);
+ return mFragmentService
+ .getFragmentHostManager(mNotificationShadeWindowView)
+ .create(QSFragment.class);
}
private void setUpPresenter() {
@@ -3770,6 +3779,9 @@
});
} else if (mDozing && !unlocking) {
mScrimController.transitionTo(ScrimState.AOD);
+ // This will cancel the keyguardFadingAway animation if it is running. We need to do
+ // this as otherwise it can remain pending and leave keyguard in a weird state.
+ mUnlockScrimCallback.onCancelled();
} else if (mKeyguardStateController.isShowing() && !isOccluded() && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
} else if (mKeyguardStateController.isShowing() && mKeyguardUpdateMonitor.isDreaming()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
deleted file mode 100644
index d318759..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.hardware.biometrics.BiometricSourceType;
-import android.os.Handler;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-
-import com.android.internal.policy.SystemBarUtils;
-import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardSecurityModel;
-import com.android.keyguard.KeyguardSecurityView;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
-import com.android.systemui.DejankUtils;
-import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.KeyguardResetCallback;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.util.ListenerSet;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * A class which manages the primary (pin/pattern/password) bouncer on the lockscreen.
- * @deprecated Use KeyguardBouncerRepository
- */
-@Deprecated
-public class KeyguardBouncer {
-
- private static final String TAG = "PrimaryKeyguardBouncer";
- static final long BOUNCER_FACE_DELAY = 1200;
- public static final float ALPHA_EXPANSION_THRESHOLD = 0.95f;
- protected final Context mContext;
- protected final ViewMediatorCallback mCallback;
- protected final ViewGroup mContainer;
- private final FalsingCollector mFalsingCollector;
- private final DismissCallbackRegistry mDismissCallbackRegistry;
- private final Handler mHandler;
- private final List<PrimaryBouncerExpansionCallback> mExpansionCallbacks = new ArrayList<>();
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardStateController mKeyguardStateController;
- private final KeyguardSecurityModel mKeyguardSecurityModel;
- private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
- private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onStrongAuthStateChanged(int userId) {
- mBouncerPromptReason = mCallback.getBouncerPromptReason();
- }
-
- @Override
- public void onLockedOutStateChanged(BiometricSourceType type) {
- if (type == BiometricSourceType.FINGERPRINT) {
- mBouncerPromptReason = mCallback.getBouncerPromptReason();
- }
- }
-
- @Override
- public void onNonStrongBiometricAllowedChanged(int userId) {
- mBouncerPromptReason = mCallback.getBouncerPromptReason();
- }
- };
- private final Runnable mRemoveViewRunnable = this::removeView;
- private final KeyguardBypassController mKeyguardBypassController;
- private KeyguardHostViewController mKeyguardViewController;
- private final ListenerSet<KeyguardResetCallback> mResetCallbacks = new ListenerSet<>();
- private final Runnable mResetRunnable = ()-> {
- if (mKeyguardViewController != null) {
- mKeyguardViewController.resetSecurityContainer();
- for (KeyguardResetCallback callback : mResetCallbacks) {
- callback.onKeyguardReset();
- }
- }
- };
-
- private int mStatusBarHeight;
- private float mExpansion = EXPANSION_HIDDEN;
- private boolean mShowingSoon;
- private int mBouncerPromptReason;
- private boolean mIsAnimatingAway;
- private boolean mIsScrimmed;
- private boolean mInitialized;
-
- private KeyguardBouncer(Context context, ViewMediatorCallback callback,
- ViewGroup container,
- DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
- PrimaryBouncerExpansionCallback expansionCallback,
- KeyguardStateController keyguardStateController,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController keyguardBypassController, @Main Handler handler,
- KeyguardSecurityModel keyguardSecurityModel,
- KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
- mContext = context;
- mCallback = callback;
- mContainer = container;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mFalsingCollector = falsingCollector;
- mDismissCallbackRegistry = dismissCallbackRegistry;
- mHandler = handler;
- mKeyguardStateController = keyguardStateController;
- mKeyguardSecurityModel = keyguardSecurityModel;
- mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
- mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
- mKeyguardBypassController = keyguardBypassController;
- mExpansionCallbacks.add(expansionCallback);
- }
-
- /**
- * Get the KeyguardBouncer expansion
- * @return 1=HIDDEN, 0=SHOWING, in between 0 and 1 means the bouncer is in transition.
- */
- public float getExpansion() {
- return mExpansion;
- }
-
- /**
- * Enable/disable only the back button
- */
- public void setBackButtonEnabled(boolean enabled) {
- int vis = mContainer.getSystemUiVisibility();
- if (enabled) {
- vis &= ~View.STATUS_BAR_DISABLE_BACK;
- } else {
- vis |= View.STATUS_BAR_DISABLE_BACK;
- }
- mContainer.setSystemUiVisibility(vis);
- }
-
- public void show(boolean resetSecuritySelection) {
- show(resetSecuritySelection, true /* scrimmed */);
- }
-
- /**
- * Shows the bouncer.
- *
- * @param resetSecuritySelection Cleans keyguard view
- * @param isScrimmed true when the bouncer show show scrimmed, false when the user will be
- * dragging it and translation should be deferred.
- */
- public void show(boolean resetSecuritySelection, boolean isScrimmed) {
- final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
- if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
- // In split system user mode, we never unlock system user.
- return;
- }
-
- try {
- Trace.beginSection("KeyguardBouncer#show");
-
- ensureView();
- mIsScrimmed = isScrimmed;
-
- // On the keyguard, we want to show the bouncer when the user drags up, but it's
- // not correct to end the falsing session. We still need to verify if those touches
- // are valid.
- // Later, at the end of the animation, when the bouncer is at the top of the screen,
- // onFullyShown() will be called and FalsingManager will stop recording touches.
- if (isScrimmed) {
- setExpansion(EXPANSION_VISIBLE);
- }
-
- if (resetSecuritySelection) {
- // showPrimarySecurityScreen() updates the current security method. This is needed
- // in case we are already showing and the current security method changed.
- showPrimarySecurityScreen();
- }
-
- if (mContainer.getVisibility() == View.VISIBLE || mShowingSoon) {
- // Calls to reset must resume the ViewControllers when in fullscreen mode
- if (needsFullscreenBouncer()) {
- mKeyguardViewController.onResume();
- }
- return;
- }
-
- final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();
- final boolean isSystemUser =
- UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
- final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
-
- // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern)
- // is set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
- if (allowDismissKeyguard && mKeyguardViewController.dismiss(activeUserId)) {
- return;
- }
-
- // This condition may indicate an error on Android, so log it.
- if (!allowDismissKeyguard) {
- Log.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != "
- + keyguardUserId);
- }
-
- mShowingSoon = true;
-
- // Split up the work over multiple frames.
- DejankUtils.removeCallbacks(mResetRunnable);
- if (mKeyguardStateController.isFaceAuthEnabled()
- && !mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
- KeyguardUpdateMonitor.getCurrentUser())
- && !needsFullscreenBouncer()
- && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
- BiometricSourceType.FACE)
- && !mKeyguardBypassController.getBypassEnabled()) {
- mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
- } else {
- DejankUtils.postAfterTraversal(mShowRunnable);
- }
-
- mKeyguardStateController.notifyBouncerShowing(true /* showing */);
- dispatchStartingToShow();
- } finally {
- Trace.endSection();
- }
- }
-
- public boolean isScrimmed() {
- return mIsScrimmed;
- }
-
- /**
- * This method must be called at the end of the bouncer animation when
- * the translation is performed manually by the user, otherwise FalsingManager
- * will never be notified and its internal state will be out of sync.
- */
- private void onFullyShown() {
- mFalsingCollector.onBouncerShown();
- if (mKeyguardViewController == null) {
- Log.e(TAG, "onFullyShown when view was null");
- } else {
- mKeyguardViewController.onResume();
- mContainer.announceForAccessibility(
- mKeyguardViewController.getAccessibilityTitleForCurrentMode());
- }
- }
-
- /**
- * @see #onFullyShown()
- */
- private void onFullyHidden() {
-
- }
-
- private void setVisibility(@View.Visibility int visibility) {
- mContainer.setVisibility(visibility);
- if (mKeyguardViewController != null) {
- mKeyguardViewController.onBouncerVisibilityChanged(visibility);
- }
- dispatchVisibilityChanged();
- }
-
- private final Runnable mShowRunnable = new Runnable() {
- @Override
- public void run() {
- setVisibility(View.VISIBLE);
- showPromptReason(mBouncerPromptReason);
- final CharSequence customMessage = mCallback.consumeCustomMessage();
- if (customMessage != null) {
- mKeyguardViewController.showErrorMessage(customMessage);
- }
- mKeyguardViewController.appear(mStatusBarHeight);
- mShowingSoon = false;
- if (mExpansion == EXPANSION_VISIBLE) {
- mKeyguardViewController.onResume();
- mKeyguardViewController.resetSecurityContainer();
- showPromptReason(mBouncerPromptReason);
- }
- }
- };
-
- /**
- * Show a string explaining why the security view needs to be solved.
- *
- * @param reason a flag indicating which string should be shown, see
- * {@link KeyguardSecurityView#PROMPT_REASON_NONE}
- * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
- */
- public void showPromptReason(int reason) {
- if (mKeyguardViewController != null) {
- mKeyguardViewController.showPromptReason(reason);
- } else {
- Log.w(TAG, "Trying to show prompt reason on empty bouncer");
- }
- }
-
- public void showMessage(String message, ColorStateList colorState) {
- if (mKeyguardViewController != null) {
- mKeyguardViewController.showMessage(message, colorState);
- } else {
- Log.w(TAG, "Trying to show message on empty bouncer");
- }
- }
-
- private void cancelShowRunnable() {
- DejankUtils.removeCallbacks(mShowRunnable);
- mHandler.removeCallbacks(mShowRunnable);
- mShowingSoon = false;
- }
-
- public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
- ensureView();
- setDismissAction(r, cancelAction);
- show(false /* resetSecuritySelection */);
- }
-
- /**
- * Set the actions to run when the keyguard is dismissed or when the dismiss is cancelled. Those
- * actions will still be run even if this bouncer is not shown, for instance when authenticating
- * with an alternate authenticator like the UDFPS.
- */
- public void setDismissAction(OnDismissAction r, Runnable cancelAction) {
- mKeyguardViewController.setOnDismissAction(r, cancelAction);
- }
-
- public void hide(boolean destroyView) {
- Trace.beginSection("KeyguardBouncer#hide");
- if (isShowing()) {
- SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
- SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
- mDismissCallbackRegistry.notifyDismissCancelled();
- }
- mIsScrimmed = false;
- mFalsingCollector.onBouncerHidden();
- mKeyguardStateController.notifyBouncerShowing(false /* showing */);
- cancelShowRunnable();
- if (mKeyguardViewController != null) {
- mKeyguardViewController.cancelDismissAction();
- mKeyguardViewController.cleanUp();
- }
- mIsAnimatingAway = false;
- setVisibility(View.INVISIBLE);
- if (destroyView) {
-
- // We have a ViewFlipper that unregisters a broadcast when being detached, which may
- // be slow because of AM lock contention during unlocking. We can delay it a bit.
- mHandler.postDelayed(mRemoveViewRunnable, 50);
- }
- Trace.endSection();
- }
-
- /**
- * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
- */
- public void startPreHideAnimation(Runnable runnable) {
- mIsAnimatingAway = true;
- if (mKeyguardViewController != null) {
- mKeyguardViewController.startDisappearAnimation(runnable);
- } else if (runnable != null) {
- runnable.run();
- }
- }
-
- /**
- * Reset the state of the view.
- */
- public void reset() {
- cancelShowRunnable();
- inflateView();
- mFalsingCollector.onBouncerHidden();
- }
-
- public void onScreenTurnedOff() {
- if (mKeyguardViewController != null && mContainer.getVisibility() == View.VISIBLE) {
- mKeyguardViewController.onPause();
- }
- }
-
- public boolean isShowing() {
- return (mShowingSoon || mContainer.getVisibility() == View.VISIBLE)
- && mExpansion == EXPANSION_VISIBLE && !isAnimatingAway();
- }
-
- /**
- * {@link #show(boolean)} was called but we're not showing yet, or being dragged.
- */
- public boolean inTransit() {
- return mShowingSoon || mExpansion != EXPANSION_HIDDEN && mExpansion != EXPANSION_VISIBLE;
- }
-
- /**
- * @return {@code true} when bouncer's pre-hide animation already started but isn't completely
- * hidden yet, {@code false} otherwise.
- */
- public boolean isAnimatingAway() {
- return mIsAnimatingAway;
- }
-
- public void prepare() {
- boolean wasInitialized = mInitialized;
- ensureView();
- if (wasInitialized) {
- showPrimarySecurityScreen();
- }
- mBouncerPromptReason = mCallback.getBouncerPromptReason();
- }
-
- private void showPrimarySecurityScreen() {
- mKeyguardViewController.showPrimarySecurityScreen();
- }
-
- /**
- * Current notification panel expansion
- * @param fraction 0 when notification panel is collapsed and 1 when expanded.
- * @see StatusBarKeyguardViewManager#onPanelExpansionChanged
- */
- public void setExpansion(float fraction) {
- float oldExpansion = mExpansion;
- boolean expansionChanged = mExpansion != fraction;
- mExpansion = fraction;
- if (mKeyguardViewController != null && !mIsAnimatingAway) {
- mKeyguardViewController.setExpansion(fraction);
- }
-
- if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) {
- onFullyShown();
- dispatchFullyShown();
- } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
- DejankUtils.postAfterTraversal(mResetRunnable);
- /*
- * There are cases where #hide() was not invoked, such as when
- * NotificationPanelViewController controls the hide animation. Make sure the state gets
- * updated by calling #hide() directly.
- */
- hide(false /* destroyView */);
- dispatchFullyHidden();
- } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
- dispatchStartingToHide();
- if (mKeyguardViewController != null) {
- mKeyguardViewController.onStartingToHide();
- }
- }
-
- if (expansionChanged) {
- dispatchExpansionChanged();
- }
- }
-
- public boolean willDismissWithAction() {
- return mKeyguardViewController != null && mKeyguardViewController.hasDismissActions();
- }
-
- public int getTop() {
- if (mKeyguardViewController == null) {
- return 0;
- }
-
- return mKeyguardViewController.getTop();
- }
-
- protected void ensureView() {
- // Removal of the view might be deferred to reduce unlock latency,
- // in this case we need to force the removal, otherwise we'll
- // end up in an unpredictable state.
- boolean forceRemoval = mHandler.hasCallbacks(mRemoveViewRunnable);
- if (!mInitialized || forceRemoval) {
- inflateView();
- }
- }
-
- protected void inflateView() {
- removeView();
- mHandler.removeCallbacks(mRemoveViewRunnable);
-
- KeyguardBouncerComponent component = mKeyguardBouncerComponentFactory.create(mContainer);
- mKeyguardViewController = component.getKeyguardHostViewController();
- mKeyguardViewController.init();
-
- mStatusBarHeight = SystemBarUtils.getStatusBarHeight(mContext);
- setVisibility(View.INVISIBLE);
-
- final WindowInsets rootInsets = mContainer.getRootWindowInsets();
- if (rootInsets != null) {
- mContainer.dispatchApplyWindowInsets(rootInsets);
- }
- mInitialized = true;
- }
-
- protected void removeView() {
- mContainer.removeAllViews();
- mInitialized = false;
- }
-
- /**
- * @return True if and only if the security method should be shown before showing the
- * notifications on Keyguard, like SIM PIN/PUK.
- */
- public boolean needsFullscreenBouncer() {
- SecurityMode mode = mKeyguardSecurityModel.getSecurityMode(
- KeyguardUpdateMonitor.getCurrentUser());
- return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
- }
-
- /**
- * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which
- * makes this method much faster.
- */
- public boolean isFullscreenBouncer() {
- if (mKeyguardViewController != null) {
- SecurityMode mode = mKeyguardViewController.getCurrentSecurityMode();
- return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
- }
- return false;
- }
-
- /**
- * WARNING: This method might cause Binder calls.
- */
- public boolean isSecure() {
- return mKeyguardSecurityModel.getSecurityMode(
- KeyguardUpdateMonitor.getCurrentUser()) != SecurityMode.None;
- }
-
- public boolean shouldDismissOnMenuPressed() {
- return mKeyguardViewController.shouldEnableMenuKey();
- }
-
- public boolean interceptMediaKey(KeyEvent event) {
- ensureView();
- return mKeyguardViewController.interceptMediaKey(event);
- }
-
- /**
- * @return true if the pre IME back event should be handled
- */
- public boolean dispatchBackKeyEventPreIme() {
- ensureView();
- return mKeyguardViewController.dispatchBackKeyEventPreIme();
- }
-
- public void notifyKeyguardAuthenticated(boolean strongAuth) {
- ensureView();
- mKeyguardViewController.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser());
- }
-
- private void dispatchFullyShown() {
- for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
- callback.onFullyShown();
- }
- }
-
- private void dispatchStartingToHide() {
- for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
- callback.onStartingToHide();
- }
- }
-
- private void dispatchStartingToShow() {
- for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
- callback.onStartingToShow();
- }
- }
-
- private void dispatchFullyHidden() {
- for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
- callback.onFullyHidden();
- }
- }
-
- private void dispatchExpansionChanged() {
- for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
- callback.onExpansionChanged(mExpansion);
- }
- }
-
- private void dispatchVisibilityChanged() {
- for (PrimaryBouncerExpansionCallback callback : mExpansionCallbacks) {
- callback.onVisibilityChanged(mContainer.getVisibility() == View.VISIBLE);
- }
- }
-
- /**
- * Apply keyguard configuration from the currently active resources. This can be called when the
- * device configuration changes, to re-apply some resources that are qualified on the device
- * configuration.
- */
- public void updateResources() {
- if (mKeyguardViewController != null) {
- mKeyguardViewController.updateResources();
- }
- }
-
- public void dump(PrintWriter pw) {
- pw.println("KeyguardBouncer");
- pw.println(" isShowing(): " + isShowing());
- pw.println(" mStatusBarHeight: " + mStatusBarHeight);
- pw.println(" mExpansion: " + mExpansion);
- pw.println(" mKeyguardViewController; " + mKeyguardViewController);
- pw.println(" mShowingSoon: " + mShowingSoon);
- pw.println(" mBouncerPromptReason: " + mBouncerPromptReason);
- pw.println(" mIsAnimatingAway: " + mIsAnimatingAway);
- pw.println(" mInitialized: " + mInitialized);
- }
-
- /** Update keyguard position based on a tapped X coordinate. */
- public void updateKeyguardPosition(float x) {
- if (mKeyguardViewController != null) {
- mKeyguardViewController.updateKeyguardPosition(x);
- }
- }
-
- public void addKeyguardResetCallback(KeyguardResetCallback callback) {
- mResetCallbacks.addIfAbsent(callback);
- }
-
- public void removeKeyguardResetCallback(KeyguardResetCallback callback) {
- mResetCallbacks.remove(callback);
- }
-
- /**
- * Adds a callback to listen to bouncer expansion updates.
- */
- public void addBouncerExpansionCallback(PrimaryBouncerExpansionCallback callback) {
- if (!mExpansionCallbacks.contains(callback)) {
- mExpansionCallbacks.add(callback);
- }
- }
-
- /**
- * Removes a previously added callback. If the callback was never added, this methood
- * does nothing.
- */
- public void removeBouncerExpansionCallback(PrimaryBouncerExpansionCallback callback) {
- mExpansionCallbacks.remove(callback);
- }
-
- /** Create a {@link KeyguardBouncer} once a container and bouncer callback are available. */
- public static class Factory {
- private final Context mContext;
- private final ViewMediatorCallback mCallback;
- private final DismissCallbackRegistry mDismissCallbackRegistry;
- private final FalsingCollector mFalsingCollector;
- private final KeyguardStateController mKeyguardStateController;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final KeyguardBypassController mKeyguardBypassController;
- private final Handler mHandler;
- private final KeyguardSecurityModel mKeyguardSecurityModel;
- private final KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
-
- @Inject
- public Factory(Context context, ViewMediatorCallback callback,
- DismissCallbackRegistry dismissCallbackRegistry, FalsingCollector falsingCollector,
- KeyguardStateController keyguardStateController,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController keyguardBypassController, @Main Handler handler,
- KeyguardSecurityModel keyguardSecurityModel,
- KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory) {
- mContext = context;
- mCallback = callback;
- mDismissCallbackRegistry = dismissCallbackRegistry;
- mFalsingCollector = falsingCollector;
- mKeyguardStateController = keyguardStateController;
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mKeyguardBypassController = keyguardBypassController;
- mHandler = handler;
- mKeyguardSecurityModel = keyguardSecurityModel;
- mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory;
- }
-
- /**
- * Construct a KeyguardBouncer that will exist in the given container.
- */
- public KeyguardBouncer create(ViewGroup container,
- PrimaryBouncerExpansionCallback expansionCallback) {
- return new KeyguardBouncer(mContext, mCallback, container,
- mDismissCallbackRegistry, mFalsingCollector, expansionCallback,
- mKeyguardStateController, mKeyguardUpdateMonitor,
- mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
- mKeyguardBouncerComponentFactory);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 4d14542..fe2a913 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -38,6 +37,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.policy.BatteryController;
import java.io.PrintWriter;
@@ -94,7 +94,8 @@
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ DisplayTracker displayTracker) {
mDarkIconColor = ctx.getColor(R.color.dark_mode_icon_color_single_tone);
mLightIconColor = ctx.getColor(R.color.light_mode_icon_color_single_tone);
mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
@@ -104,7 +105,7 @@
mNavigationMode = mode;
});
- if (ctx.getDisplayId() == DEFAULT_DISPLAY) {
+ if (ctx.getDisplayId() == displayTracker.getDefaultDisplayId()) {
dumpManager.registerDumpable(getClass().getSimpleName(), this);
}
}
@@ -317,24 +318,27 @@
private final BatteryController mBatteryController;
private final NavigationModeController mNavModeController;
private final DumpManager mDumpManager;
+ private final DisplayTracker mDisplayTracker;
@Inject
public Factory(
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
- DumpManager dumpManager) {
+ DumpManager dumpManager,
+ DisplayTracker displayTracker) {
mDarkIconDispatcher = darkIconDispatcher;
mBatteryController = batteryController;
mNavModeController = navModeController;
mDumpManager = dumpManager;
+ mDisplayTracker = displayTracker;
}
/** Create an {@link LightBarController} */
public LightBarController create(Context context) {
return new LightBarController(context, mDarkIconDispatcher, mBatteryController,
- mNavModeController, mDumpManager);
+ mNavModeController, mDumpManager, mDisplayTracker);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 24ad55d..11863627 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -501,7 +501,7 @@
@VisibleForTesting
protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) {
if (mStatusBarPipelineFlags.useNewWifiIcon()) {
- throw new IllegalStateException("Attempting to add a mobile icon while the new "
+ throw new IllegalStateException("Attempting to add a wifi icon while the new "
+ "icons are enabled is not supported");
}
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 8e22bf4..fd46571 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -129,7 +129,6 @@
private final ConfigurationController mConfigurationController;
private final NavigationModeController mNavigationModeController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
- private final KeyguardBouncer.Factory mKeyguardBouncerFactory;
private final KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
private final DreamOverlayStateController mDreamOverlayStateController;
@Nullable
@@ -206,28 +205,28 @@
Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
}
onBackPressed();
- if (shouldPlayBackAnimation()) {
+ if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
mPrimaryBouncerView.getDelegate().getBackCallback().onBackInvoked();
}
}
@Override
public void onBackProgressed(BackEvent event) {
- if (shouldPlayBackAnimation()) {
+ if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
mPrimaryBouncerView.getDelegate().getBackCallback().onBackProgressed(event);
}
}
@Override
public void onBackCancelled() {
- if (shouldPlayBackAnimation()) {
+ if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
mPrimaryBouncerView.getDelegate().getBackCallback().onBackCancelled();
}
}
@Override
public void onBackStarted(BackEvent event) {
- if (shouldPlayBackAnimation()) {
+ if (shouldPlayBackAnimation() && mPrimaryBouncerView.getDelegate() != null) {
mPrimaryBouncerView.getDelegate().getBackCallback().onBackStarted(event);
}
}
@@ -256,7 +255,6 @@
private View mNotificationContainer;
- @Nullable protected KeyguardBouncer mPrimaryBouncer;
protected boolean mRemoteInputActive;
private boolean mGlobalActionsVisible = false;
private boolean mLastGlobalActionsVisible = false;
@@ -281,7 +279,6 @@
private boolean mLastScreenOffAnimationPlaying;
private float mQsExpansion;
final Set<KeyguardViewManagerCallback> mCallbacks = new HashSet<>();
- private boolean mIsModernBouncerEnabled;
private boolean mIsUnoccludeTransitionFlagEnabled;
private boolean mIsModernAlternateBouncerEnabled;
private boolean mIsBackAnimationEnabled;
@@ -329,7 +326,6 @@
NotificationShadeWindowController notificationShadeWindowController,
KeyguardStateController keyguardStateController,
NotificationMediaManager notificationMediaManager,
- KeyguardBouncer.Factory keyguardBouncerFactory,
KeyguardMessageAreaController.Factory keyguardMessageAreaFactory,
Optional<SysUIUnfoldComponent> sysUIUnfoldComponent,
Lazy<ShadeController> shadeController,
@@ -352,7 +348,6 @@
mKeyguardUpdateManager = keyguardUpdateMonitor;
mStatusBarStateController = sysuiStatusBarStateController;
mDockManager = dockManager;
- mKeyguardBouncerFactory = keyguardBouncerFactory;
mKeyguardMessageAreaFactory = keyguardMessageAreaFactory;
mShadeController = shadeController;
mLatencyTracker = latencyTracker;
@@ -362,7 +357,6 @@
mPrimaryBouncerView = primaryBouncerView;
mFoldAodAnimationController = sysUIUnfoldComponent
.map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
- mIsModernBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_BOUNCER);
mIsUnoccludeTransitionFlagEnabled = featureFlags.isEnabled(Flags.UNOCCLUSION_TRANSITION);
mIsModernAlternateBouncerEnabled = featureFlags.isEnabled(Flags.MODERN_ALTERNATE_BOUNCER);
mAlternateBouncerInteractor = alternateBouncerInteractor;
@@ -381,11 +375,7 @@
mBiometricUnlockController = biometricUnlockController;
ViewGroup container = mCentralSurfaces.getBouncerContainer();
- if (mIsModernBouncerEnabled) {
- mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback);
- } else {
- mPrimaryBouncer = mKeyguardBouncerFactory.create(container, mExpansionCallback);
- }
+ mPrimaryBouncerCallbackInteractor.addBouncerExpansionCallback(mExpansionCallback);
mNotificationPanelViewController = notificationPanelViewController;
if (shadeExpansionStateManager != null) {
shadeExpansionStateManager.addExpansionListener(this);
@@ -552,11 +542,7 @@
* show if any subsequent events are to be handled.
*/
if (beginShowingBouncer(event)) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
- } else {
- mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
- }
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
}
if (!primaryBouncerIsOrWillBeShowing()) {
@@ -564,17 +550,9 @@
}
if (mKeyguardStateController.isShowing()) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.setExpansion(fraction);
- } else {
- mPrimaryBouncerInteractor.setPanelExpansion(fraction);
- }
+ mPrimaryBouncerInteractor.setPanelExpansion(fraction);
} else {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.setExpansion(EXPANSION_HIDDEN);
- } else {
- mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN);
- }
+ mPrimaryBouncerInteractor.setPanelExpansion(EXPANSION_HIDDEN);
}
}
@@ -604,24 +582,17 @@
/**
* Shows the notification keyguard or the bouncer depending on
- * {@link KeyguardBouncer#needsFullscreenBouncer()}.
+ * {@link #needsFullscreenBouncer()}.
*/
protected void showBouncerOrKeyguard(boolean hideBouncerWhenShowing) {
if (needsFullscreenBouncer() && !mDozing) {
// The keyguard might be showing (already). So we need to hide it.
mCentralSurfaces.hideKeyguard();
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.show(true /* resetSecuritySelection */);
- } else {
- mPrimaryBouncerInteractor.show(true);
- }
+ mPrimaryBouncerInteractor.show(true);
} else {
mCentralSurfaces.showKeyguard();
if (hideBouncerWhenShowing) {
hideBouncer(false /* destroyView */);
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.prepare();
- }
}
}
updateStates();
@@ -648,11 +619,7 @@
*/
@VisibleForTesting
void hideBouncer(boolean destroyView) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.hide(destroyView);
- } else {
- mPrimaryBouncerInteractor.hide();
- }
+ mPrimaryBouncerInteractor.hide();
if (mKeyguardStateController.isShowing()) {
// If we were showing the bouncer and then aborting, we need to also clear out any
// potential actions unless we actually unlocked.
@@ -671,11 +638,7 @@
hideAlternateBouncer(false);
if (mKeyguardStateController.isShowing() && !isBouncerShowing()) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.show(false /* resetSecuritySelection */, scrimmed);
- } else {
- mPrimaryBouncerInteractor.show(scrimmed);
- }
+ mPrimaryBouncerInteractor.show(scrimmed);
}
updateStates();
}
@@ -708,13 +671,8 @@
// instead of the bouncer.
if (mAlternateBouncerInteractor.canShowAlternateBouncerForFingerprint()) {
if (!afterKeyguardGone) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.setDismissAction(mAfterKeyguardGoneAction,
- mKeyguardGoneCancelAction);
- } else {
- mPrimaryBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction,
- mKeyguardGoneCancelAction);
- }
+ mPrimaryBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction,
+ mKeyguardGoneCancelAction);
mAfterKeyguardGoneAction = null;
mKeyguardGoneCancelAction = null;
}
@@ -726,22 +684,13 @@
if (afterKeyguardGone) {
// we'll handle the dismiss action after keyguard is gone, so just show the
// bouncer
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.show(false /* resetSecuritySelection */);
- } else {
- mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
- }
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
} else {
// after authentication success, run dismiss action with the option to defer
// hiding the keyguard based on the return value of the OnDismissAction
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.showWithDismissAction(mAfterKeyguardGoneAction,
- mKeyguardGoneCancelAction);
- } else {
- mPrimaryBouncerInteractor.setDismissAction(
- mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
- mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
- }
+ mPrimaryBouncerInteractor.setDismissAction(
+ mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
+ mPrimaryBouncerInteractor.show(/* isScrimmed= */true);
// bouncer will handle the dismiss action, so we no longer need to track it here
mAfterKeyguardGoneAction = null;
mKeyguardGoneCancelAction = null;
@@ -841,11 +790,7 @@
@Override
public void onFinishedGoingToSleep() {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.onScreenTurnedOff();
- } else {
- mPrimaryBouncerInteractor.onScreenTurnedOff();
- }
+ mPrimaryBouncerInteractor.onScreenTurnedOff();
}
@Override
@@ -939,11 +884,7 @@
@Override
public void startPreHideAnimation(Runnable finishRunnable) {
if (primaryBouncerIsShowing()) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.startPreHideAnimation(finishRunnable);
- } else {
- mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable);
- }
+ mPrimaryBouncerInteractor.startDisappearAnimation(finishRunnable);
mNotificationPanelViewController.startBouncerPreHideAnimation();
// We update the state (which will show the keyguard) only if an animation will run on
@@ -1051,17 +992,7 @@
}
public void onThemeChanged() {
- if (mIsModernBouncerEnabled) {
- updateResources();
- return;
- }
- boolean wasShowing = primaryBouncerIsShowing();
- boolean wasScrimmed = primaryBouncerIsScrimmed();
-
- hideBouncer(true /* destroyView */);
- mPrimaryBouncer.prepare();
-
- if (wasShowing) showPrimaryBouncer(wasScrimmed);
+ updateResources();
}
public void onKeyguardFadedAway() {
@@ -1106,10 +1037,6 @@
* WARNING: This method might cause Binder calls.
*/
public boolean isSecure() {
- if (mPrimaryBouncer != null) {
- return mPrimaryBouncer.isSecure();
- }
-
return mKeyguardSecurityModel.getSecurityMode(
KeyguardUpdateMonitor.getCurrentUser()) != KeyguardSecurityModel.SecurityMode.None;
}
@@ -1164,10 +1091,8 @@
}
public boolean isFullscreenBouncer() {
- if (mPrimaryBouncerView.getDelegate() != null) {
- return mPrimaryBouncerView.getDelegate().isFullScreenBouncer();
- }
- return mPrimaryBouncer != null && mPrimaryBouncer.isFullscreenBouncer();
+ return mPrimaryBouncerView.getDelegate() != null
+ && mPrimaryBouncerView.getDelegate().isFullScreenBouncer();
}
/**
@@ -1223,17 +1148,9 @@
!= (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive)
|| mFirstUpdate) {
if (primaryBouncerDismissible || !showing || remoteInputActive) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.setBackButtonEnabled(true);
- } else {
- mPrimaryBouncerInteractor.setBackButtonEnabled(true);
- }
+ mPrimaryBouncerInteractor.setBackButtonEnabled(true);
} else {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.setBackButtonEnabled(false);
- } else {
- mPrimaryBouncerInteractor.setBackButtonEnabled(false);
- }
+ mPrimaryBouncerInteractor.setBackButtonEnabled(false);
}
}
@@ -1327,27 +1244,21 @@
}
public boolean shouldDismissOnMenuPressed() {
- if (mPrimaryBouncerView.getDelegate() != null) {
- return mPrimaryBouncerView.getDelegate().shouldDismissOnMenuPressed();
- }
- return mPrimaryBouncer != null && mPrimaryBouncer.shouldDismissOnMenuPressed();
+ return mPrimaryBouncerView.getDelegate() != null
+ && mPrimaryBouncerView.getDelegate().shouldDismissOnMenuPressed();
}
public boolean interceptMediaKey(KeyEvent event) {
- if (mPrimaryBouncerView.getDelegate() != null) {
- return mPrimaryBouncerView.getDelegate().interceptMediaKey(event);
- }
- return mPrimaryBouncer != null && mPrimaryBouncer.interceptMediaKey(event);
+ return mPrimaryBouncerView.getDelegate() != null
+ && mPrimaryBouncerView.getDelegate().interceptMediaKey(event);
}
/**
* @return true if the pre IME back event should be handled
*/
public boolean dispatchBackKeyEventPreIme() {
- if (mPrimaryBouncerView.getDelegate() != null) {
- return mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme();
- }
- return mPrimaryBouncer != null && mPrimaryBouncer.dispatchBackKeyEventPreIme();
+ return mPrimaryBouncerView.getDelegate() != null
+ && mPrimaryBouncerView.getDelegate().dispatchBackKeyEventPreIme();
}
public void readyForKeyguardDone() {
@@ -1393,11 +1304,7 @@
* fingerprint.
*/
public void notifyKeyguardAuthenticated(boolean strongAuth) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.notifyKeyguardAuthenticated(strongAuth);
- } else {
- mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
- }
+ mPrimaryBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
if (mAlternateBouncerInteractor.isVisibleState()) {
hideAlternateBouncer(false);
@@ -1412,11 +1319,7 @@
mKeyguardMessageAreaController.setMessage(message);
}
} else {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.showMessage(message, colorState);
- } else {
- mPrimaryBouncerInteractor.showMessage(message, colorState);
- }
+ mPrimaryBouncerInteractor.showMessage(message, colorState);
}
}
@@ -1472,11 +1375,7 @@
* configuration.
*/
public void updateResources() {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.updateResources();
- } else {
- mPrimaryBouncerInteractor.updateResources();
- }
+ mPrimaryBouncerInteractor.updateResources();
}
public void dump(PrintWriter pw) {
@@ -1494,11 +1393,6 @@
pw.println(" " + callback);
}
- if (mPrimaryBouncer != null) {
- pw.println("PrimaryBouncer:");
- mPrimaryBouncer.dump(pw);
- }
-
if (mOccludingAppBiometricUI != null) {
pw.println("mOccludingAppBiometricUI:");
mOccludingAppBiometricUI.dump(pw);
@@ -1548,11 +1442,6 @@
}
}
- @Nullable
- public KeyguardBouncer getPrimaryBouncer() {
- return mPrimaryBouncer;
- }
-
/**
* For any touches on the NPVC, show the primary bouncer if the alternate bouncer is currently
* showing.
@@ -1571,11 +1460,7 @@
/** Update keyguard position based on a tapped X coordinate. */
public void updateKeyguardPosition(float x) {
- if (mPrimaryBouncer != null) {
- mPrimaryBouncer.updateKeyguardPosition(x);
- } else {
- mPrimaryBouncerInteractor.setKeyguardPosition(x);
- }
+ mPrimaryBouncerInteractor.setKeyguardPosition(x);
}
private static class DismissWithActionRequest {
@@ -1615,56 +1500,35 @@
* Returns if bouncer expansion is between 0 and 1 non-inclusive.
*/
public boolean isPrimaryBouncerInTransit() {
- if (mPrimaryBouncer != null) {
- return mPrimaryBouncer.inTransit();
- } else {
- return mPrimaryBouncerInteractor.isInTransit();
- }
+ return mPrimaryBouncerInteractor.isInTransit();
}
/**
* Returns if bouncer is showing
*/
public boolean primaryBouncerIsShowing() {
- if (mPrimaryBouncer != null) {
- return mPrimaryBouncer.isShowing();
- } else {
- return mPrimaryBouncerInteractor.isFullyShowing();
- }
+ return mPrimaryBouncerInteractor.isFullyShowing();
}
/**
* Returns if bouncer is scrimmed
*/
public boolean primaryBouncerIsScrimmed() {
- if (mPrimaryBouncer != null) {
- return mPrimaryBouncer.isScrimmed();
- } else {
- return mPrimaryBouncerInteractor.isScrimmed();
- }
+ return mPrimaryBouncerInteractor.isScrimmed();
}
/**
* Returns if bouncer is animating away
*/
public boolean bouncerIsAnimatingAway() {
- if (mPrimaryBouncer != null) {
- return mPrimaryBouncer.isAnimatingAway();
- } else {
- return mPrimaryBouncerInteractor.isAnimatingAway();
- }
-
+ return mPrimaryBouncerInteractor.isAnimatingAway();
}
/**
* Returns if bouncer will dismiss with action
*/
public boolean primaryBouncerWillDismissWithAction() {
- if (mPrimaryBouncer != null) {
- return mPrimaryBouncer.willDismissWithAction();
- } else {
- return mPrimaryBouncerInteractor.willDismissWithAction();
- }
+ return mPrimaryBouncerInteractor.willDismissWithAction();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
index ae48c2d3..50cce45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowCallback.java
@@ -17,5 +17,5 @@
public interface StatusBarWindowCallback {
void onStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing,
- boolean isDozing, boolean panelExpanded);
+ boolean isDozing, boolean panelExpanded, boolean isDreaming);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
index 2c8677d..2d80edb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
@@ -19,14 +19,14 @@
import android.content.Context
import android.util.AttributeSet
import android.widget.ImageView
-import android.widget.LinearLayout
import android.widget.TextView
import com.android.systemui.R
+import com.android.systemui.common.ui.view.LaunchableLinearLayout
class StatusBarUserSwitcherContainer(
context: Context?,
attrs: AttributeSet?
-) : LinearLayout(context, attrs) {
+) : LaunchableLinearLayout(context, attrs) {
lateinit var text: TextView
private set
lateinit var avatar: ImageView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 510482d..39ad31f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -53,7 +53,7 @@
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
-import com.android.systemui.util.kotlin.pairwiseBy
+import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -66,10 +66,10 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
@@ -287,22 +287,13 @@
*/
@SuppressLint("MissingPermission")
override val activeSubChangedInGroupEvent =
- flow {
- activeMobileDataSubscriptionId.pairwiseBy { prevVal: Int, newVal: Int ->
- if (!defaultMobileNetworkConnectivity.value.isValidated) {
- return@pairwiseBy
- }
- val prevSub = subscriptionManager.getActiveSubscriptionInfo(prevVal)
- val nextSub = subscriptionManager.getActiveSubscriptionInfo(newVal)
+ activeMobileDataSubscriptionId
+ .pairwise()
+ .mapNotNull { (prevVal: Int, newVal: Int) ->
+ val prevSub = subscriptionManager.getActiveSubscriptionInfo(prevVal)?.groupUuid
+ val nextSub = subscriptionManager.getActiveSubscriptionInfo(newVal)?.groupUuid
- if (prevSub == null || nextSub == null) {
- return@pairwiseBy
- }
-
- if (prevSub.groupUuid != null && prevSub.groupUuid == nextSub.groupUuid) {
- emit(Unit)
- }
- }
+ if (prevSub != null && prevSub == nextSub) Unit else null
}
.flowOn(bgDispatcher)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
index d3ff357..491f3a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
@@ -97,15 +97,20 @@
)
}
- fun logOnCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
+ fun logOnCapabilitiesChanged(
+ network: Network,
+ networkCapabilities: NetworkCapabilities,
+ isDefaultNetworkCallback: Boolean,
+ ) {
buffer.log(
SB_LOGGING_TAG,
LogLevel.INFO,
{
+ bool1 = isDefaultNetworkCallback
int1 = network.getNetId()
str1 = networkCapabilities.toString()
},
- { "onCapabilitiesChanged: net=$int1 capabilities=$str1" }
+ { "onCapabilitiesChanged[default=$bool1]: net=$int1 capabilities=$str1" }
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index d26499c..8669047 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -114,13 +114,17 @@
network: Network,
networkCapabilities: NetworkCapabilities
) {
+ logger.logOnCapabilitiesChanged(
+ network,
+ networkCapabilities,
+ isDefaultNetworkCallback = true,
+ )
+
// This method will always be called immediately after the network
// becomes the default, in addition to any time the capabilities change
// while the network is the default.
- // If this network contains valid wifi info, then wifi is the default
- // network.
- val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
- trySend(wifiInfo != null)
+ // If this network is a wifi network, then wifi is the default network.
+ trySend(isWifiNetwork(networkCapabilities))
}
override fun onLost(network: Network) {
@@ -152,7 +156,11 @@
network: Network,
networkCapabilities: NetworkCapabilities
) {
- logger.logOnCapabilitiesChanged(network, networkCapabilities)
+ logger.logOnCapabilitiesChanged(
+ network,
+ networkCapabilities,
+ isDefaultNetworkCallback = false,
+ )
wifiNetworkChangeEvents.tryEmit(Unit)
@@ -253,16 +261,30 @@
networkCapabilities: NetworkCapabilities
): WifiInfo? {
return when {
- networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
- networkCapabilities.transportInfo as WifiInfo?
networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
// Sometimes, cellular networks can act as wifi networks (known as VCN --
// virtual carrier network). So, see if this cellular network has wifi info.
Utils.tryGetWifiInfoForVcn(networkCapabilities)
+ networkCapabilities.hasTransport(TRANSPORT_WIFI) ->
+ if (networkCapabilities.transportInfo is WifiInfo) {
+ networkCapabilities.transportInfo as WifiInfo
+ } else {
+ null
+ }
else -> null
}
}
+ /** True if these capabilities represent a wifi network. */
+ private fun isWifiNetwork(networkCapabilities: NetworkCapabilities): Boolean {
+ return when {
+ networkCapabilities.hasTransport(TRANSPORT_WIFI) -> true
+ networkCapabilities.hasTransport(TRANSPORT_CELLULAR) ->
+ Utils.tryGetWifiInfoForVcn(networkCapabilities) != null
+ else -> false
+ }
+ }
+
private fun createWifiNetworkModel(
wifiInfo: WifiInfo,
network: Network,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index 9946b4b..5dcafb3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.policy;
import android.annotation.WorkerThread;
-import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
@@ -255,7 +254,6 @@
setTorchMode(enabled);
mSecureSettings.putInt(Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
mSecureSettings.putInt(Secure.FLASHLIGHT_ENABLED, enabled ? 1 : 0);
- mBroadcastSender.sendBroadcast(new Intent(ACTION_FLASHLIGHT_CHANGED));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index e0d780a..7a4e35f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -48,6 +48,7 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentService;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.util.JankMonitorTransitionProgressListener;
@@ -73,6 +74,7 @@
private boolean mIsAttached;
private final ViewGroup mStatusBarWindowView;
+ private final FragmentService mFragmentService;
// The container in which we should run launch animations started from the status bar and
// expanding into the opening window.
private final ViewGroup mLaunchAnimationContainer;
@@ -86,6 +88,7 @@
WindowManager windowManager,
IWindowManager iWindowManager,
StatusBarContentInsetsProvider contentInsetsProvider,
+ FragmentService fragmentService,
@Main Resources resources,
Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider) {
mContext = context;
@@ -93,6 +96,7 @@
mIWindowManager = iWindowManager;
mContentInsetsProvider = contentInsetsProvider;
mStatusBarWindowView = statusBarWindowView;
+ mFragmentService = fragmentService;
mLaunchAnimationContainer = mStatusBarWindowView.findViewById(
R.id.status_bar_launch_animation_container);
mLpChanged = new WindowManager.LayoutParams();
@@ -157,7 +161,7 @@
/** Returns a fragment host manager for the status bar window view. */
public FragmentHostManager getFragmentHostManager() {
- return FragmentHostManager.get(mStatusBarWindowView);
+ return mFragmentService.getFragmentHostManager(mStatusBarWindowView);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index df8d161..1065d33 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -327,7 +327,7 @@
// appropriately.
activeViews.remove(displayInfo)
listeners.forEach {
- it.onInfoPermanentlyRemoved(id)
+ it.onInfoPermanentlyRemoved(id, removalReason)
}
// No need to time the view out since it's already gone
@@ -393,7 +393,7 @@
activeViews.remove(it)
logger.logViewExpiration(it.info)
listeners.forEach { listener ->
- listener.onInfoPermanentlyRemoved(it.info.id)
+ listener.onInfoPermanentlyRemoved(it.info.id, REMOVAL_REASON_TIME_EXPIRED)
}
}
}
@@ -457,7 +457,7 @@
* Called whenever a [DisplayInfo] with the given [id] has been removed and will never be
* displayed again (unless another call to [updateView] is made).
*/
- fun onInfoPermanentlyRemoved(id: String)
+ fun onInfoPermanentlyRemoved(id: String, reason: String)
}
/** A container for all the display-related state objects. */
@@ -494,6 +494,7 @@
}
private const val REMOVAL_REASON_TIMEOUT = "TIMEOUT"
+private const val REMOVAL_REASON_TIME_EXPIRED = "TIMEOUT_EXPIRED_BEFORE_REDISPLAY"
private const val MIN_REQUIRED_TIME_FOR_REDISPLAY = 1000
private data class IconInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index 9e0bbb7..46f13cc 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -206,31 +206,44 @@
}
override fun animateViewIn(view: ViewGroup) {
- ViewHierarchyAnimator.animateAddition(
- view.getInnerView(),
- ViewHierarchyAnimator.Hotspot.TOP,
- Interpolators.EMPHASIZED_DECELERATE,
- duration = ANIMATION_IN_DURATION,
- includeMargins = true,
- includeFadeIn = true,
- // We can only request focus once the animation finishes.
- onAnimationEnd = {
- maybeGetAccessibilityFocus(view.getTag(INFO_TAG) as ChipbarInfo?, view)
- },
- )
+ val onAnimationEnd = Runnable {
+ maybeGetAccessibilityFocus(view.getTag(INFO_TAG) as ChipbarInfo?, view)
+ }
+ val added =
+ ViewHierarchyAnimator.animateAddition(
+ view.getInnerView(),
+ ViewHierarchyAnimator.Hotspot.TOP,
+ Interpolators.EMPHASIZED_DECELERATE,
+ duration = ANIMATION_IN_DURATION,
+ includeMargins = true,
+ includeFadeIn = true,
+ // We can only request focus once the animation finishes.
+ onAnimationEnd = onAnimationEnd,
+ )
+ // If the view doesn't get animated, the [onAnimationEnd] runnable won't get run. So, just
+ // run it immediately.
+ if (!added) {
+ onAnimationEnd.run()
+ }
}
override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
val innerView = view.getInnerView()
innerView.accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_NONE
- ViewHierarchyAnimator.animateRemoval(
- innerView,
- ViewHierarchyAnimator.Hotspot.TOP,
- Interpolators.EMPHASIZED_ACCELERATE,
- ANIMATION_OUT_DURATION,
- includeMargins = true,
- onAnimationEnd,
- )
+ val removed =
+ ViewHierarchyAnimator.animateRemoval(
+ innerView,
+ ViewHierarchyAnimator.Hotspot.TOP,
+ Interpolators.EMPHASIZED_ACCELERATE,
+ ANIMATION_OUT_DURATION,
+ includeMargins = true,
+ onAnimationEnd,
+ )
+ // If the view doesn't get animated, the [onAnimationEnd] runnable won't get run. So, just
+ // run it immediately.
+ if (!removed) {
+ onAnimationEnd.run()
+ }
updateGestureListening()
}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt
index 6e3cb48..9dbc4b3 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandler.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.view.MotionEvent
import android.view.View
+import com.android.systemui.settings.DisplayTracker
import com.android.systemui.statusbar.gesture.SwipeUpGestureHandler
import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
import com.android.systemui.util.boundsOnScreen
@@ -31,8 +32,9 @@
*/
class SwipeChipbarAwayGestureHandler(
context: Context,
+ displayTracker: DisplayTracker,
logger: SwipeUpGestureLogger,
-) : SwipeUpGestureHandler(context, logger, loggerTag = LOGGER_TAG) {
+) : SwipeUpGestureHandler(context, displayTracker, logger, loggerTag = LOGGER_TAG) {
private var viewFetcher: () -> View? = { null }
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
index 933c060..b1be404 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/dagger/TemporaryDisplayModule.kt
@@ -21,6 +21,7 @@
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.media.taptotransfer.MediaTttFlags
import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.settings.DisplayTracker
import com.android.systemui.statusbar.gesture.SwipeUpGestureLogger
import com.android.systemui.temporarydisplay.chipbar.SwipeChipbarAwayGestureHandler
import dagger.Module
@@ -41,10 +42,11 @@
fun provideSwipeChipbarAwayGestureHandler(
mediaTttFlags: MediaTttFlags,
context: Context,
+ displayTracker: DisplayTracker,
logger: SwipeUpGestureLogger,
): SwipeChipbarAwayGestureHandler? {
return if (mediaTttFlags.isMediaTttDismissGestureEnabled()) {
- SwipeChipbarAwayGestureHandler(context, logger)
+ SwipeChipbarAwayGestureHandler(context, displayTracker, logger)
} else {
null
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
index 79811c5..2475890 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/RadioListPreference.java
@@ -28,8 +28,9 @@
import androidx.preference.PreferenceScreen;
import com.android.settingslib.Utils;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentService;
import java.util.Objects;
@@ -74,7 +75,7 @@
RadioFragment f = new RadioFragment();
f.setPreference(this);
- FragmentHostManager.get(v).getFragmentManager()
+ Dependency.get(FragmentService.class).getFragmentHostManager(v).getFragmentManager()
.beginTransaction()
.add(android.R.id.content, f)
.commit();
@@ -86,8 +87,10 @@
Bundle savedInstanceState) {
super.onDialogStateRestored(fragment, dialog, savedInstanceState);
View view = dialog.findViewById(R.id.content);
- RadioFragment radioFragment = (RadioFragment) FragmentHostManager.get(view)
- .getFragmentManager().findFragmentById(R.id.content);
+ RadioFragment radioFragment = (RadioFragment) Dependency.get(FragmentService.class)
+ .getFragmentHostManager(view)
+ .getFragmentManager()
+ .findFragmentById(R.id.content);
if (radioFragment != null) {
radioFragment.setPreference(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 0069bb5..19a0866 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -38,6 +38,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.settings.DisplayTracker
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.LinearLightRevealEffect
@@ -68,6 +69,7 @@
@Main private val executor: Executor,
private val threadFactory: ThreadFactory,
private val rotationChangeProvider: RotationChangeProvider,
+ private val displayTracker: DisplayTracker
) {
private val transitionListener = TransitionListener()
@@ -104,7 +106,7 @@
.setName("unfold-overlay-container")
displayAreaHelper.get().attachToRootDisplayArea(
- Display.DEFAULT_DISPLAY,
+ displayTracker.defaultDisplayId,
containerBuilder
) { builder ->
executor.execute {
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index c0f0390..8cb4deb 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -174,7 +174,7 @@
val callback =
object : UserTracker.Callback {
- override fun onUserChanged(newUser: Int, userContext: Context) {
+ override fun onUserChanging(newUser: Int, userContext: Context) {
send()
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index d54de3fa..c2727fc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -14,8 +14,6 @@
package com.android.systemui.util;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import android.Manifest;
import android.content.Context;
import android.content.Intent;
@@ -26,6 +24,7 @@
import com.android.internal.policy.SystemBarUtils;
import com.android.systemui.R;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shared.system.QuickStepContract;
import java.util.List;
@@ -71,8 +70,9 @@
* {@link android.view.WindowManagerPolicyConstants#NAV_BAR_MODE_GESTURAL} AND
* the context is that of the default display
*/
- public static boolean isGesturalModeOnDefaultDisplay(Context context, int navMode) {
- return context.getDisplayId() == DEFAULT_DISPLAY
+ public static boolean isGesturalModeOnDefaultDisplay(Context context,
+ DisplayTracker displayTracker, int navMode) {
+ return context.getDisplayId() == displayTracker.getDefaultDisplayId()
&& QuickStepContract.isGesturalMode(navMode);
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
index 08ee0af..56c5d3b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
@@ -27,6 +27,8 @@
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
+import com.android.systemui.animation.LaunchableView
+import com.android.systemui.animation.LaunchableViewDelegate
import com.android.systemui.statusbar.CrossFadeHelper
/**
@@ -38,7 +40,7 @@
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
-) : ConstraintLayout(context, attrs, defStyleAttr) {
+) : ConstraintLayout(context, attrs, defStyleAttr), LaunchableView {
private val boundsRect = Rect()
private val originalGoneChildrenSet: MutableSet<Int> = mutableSetOf()
@@ -50,7 +52,11 @@
private var desiredMeasureWidth = 0
private var desiredMeasureHeight = 0
- private var transitionVisibility = View.VISIBLE
+ private val delegate =
+ LaunchableViewDelegate(
+ this,
+ superSetVisibility = { super.setVisibility(it) },
+ )
/**
* The measured state of this view which is the one we will lay ourselves out with. This
@@ -83,11 +89,12 @@
}
}
- override fun setTransitionVisibility(visibility: Int) {
- // We store the last transition visibility assigned to this view to restore it later if
- // necessary.
- super.setTransitionVisibility(visibility)
- transitionVisibility = visibility
+ override fun setShouldBlockVisibilityChanges(block: Boolean) {
+ delegate.setShouldBlockVisibilityChanges(block)
+ }
+
+ override fun setVisibility(visibility: Int) {
+ delegate.setVisibility(visibility)
}
override fun onFinishInflate() {
@@ -173,14 +180,6 @@
translationY = currentState.translation.y
CrossFadeHelper.fadeIn(this, currentState.alpha)
-
- // CrossFadeHelper#fadeIn will change this view visibility, which overrides the transition
- // visibility. We set the transition visibility again to make sure that this view plays well
- // with GhostView, which sets the transition visibility and is used for activity launch
- // animations.
- if (transitionVisibility != View.VISIBLE) {
- setTransitionVisibility(transitionVisibility)
- }
}
private fun applyCurrentStateOnPredraw() {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 7033ccd..5d896cb 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -236,7 +236,8 @@
// Store callback in a field so it won't get GC'd
mStatusBarWindowCallback =
- (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded) ->
+ (keyguardShowing, keyguardOccluded, bouncerShowing, isDozing, panelExpanded,
+ isDreaming) ->
mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 8ef98f0..bd60401 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -16,8 +16,6 @@
package com.android.systemui.wmshell;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
@@ -50,6 +48,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.notetask.NoteTaskInitializer;
+import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.statusbar.CommandQueue;
@@ -124,6 +123,7 @@
private final WakefulnessLifecycle mWakefulnessLifecycle;
private final ProtoTracer mProtoTracer;
private final UserTracker mUserTracker;
+ private final DisplayTracker mDisplayTracker;
private final NoteTaskInitializer mNoteTaskInitializer;
private final Executor mSysUiMainExecutor;
@@ -186,6 +186,7 @@
ProtoTracer protoTracer,
WakefulnessLifecycle wakefulnessLifecycle,
UserTracker userTracker,
+ DisplayTracker displayTracker,
NoteTaskInitializer noteTaskInitializer,
@Main Executor sysUiMainExecutor) {
mContext = context;
@@ -203,6 +204,7 @@
mWakefulnessLifecycle = wakefulnessLifecycle;
mProtoTracer = protoTracer;
mUserTracker = userTracker;
+ mDisplayTracker = displayTracker;
mNoteTaskInitializer = noteTaskInitializer;
mSysUiMainExecutor = sysUiMainExecutor;
}
@@ -268,7 +270,7 @@
public void onStartTransition(boolean isEntering) {
mSysUiMainExecutor.execute(() -> {
mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
- true).commitUpdate(DEFAULT_DISPLAY);
+ true).commitUpdate(mDisplayTracker.getDefaultDisplayId());
});
}
@@ -276,7 +278,7 @@
public void onStartFinished(Rect bounds) {
mSysUiMainExecutor.execute(() -> {
mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
- true).commitUpdate(DEFAULT_DISPLAY);
+ true).commitUpdate(mDisplayTracker.getDefaultDisplayId());
});
}
@@ -284,7 +286,7 @@
public void onStopFinished(Rect bounds) {
mSysUiMainExecutor.execute(() -> {
mSysUiState.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE,
- false).commitUpdate(DEFAULT_DISPLAY);
+ false).commitUpdate(mDisplayTracker.getDefaultDisplayId());
});
}
});
@@ -333,7 +335,8 @@
@Override
public void setImeWindowStatus(int displayId, IBinder token, int vis,
int backDisposition, boolean showImeSwitcher) {
- if (displayId == DEFAULT_DISPLAY && (vis & InputMethodService.IME_VISIBLE) != 0) {
+ if (displayId == mDisplayTracker.getDefaultDisplayId()
+ && (vis & InputMethodService.IME_VISIBLE) != 0) {
oneHanded.stopOneHanded(
OneHandedUiEventLogger.EVENT_ONE_HANDED_TRIGGER_POP_IME_OUT);
}
@@ -346,7 +349,7 @@
@Override
public void onVisibilityChanged(boolean hasFreeformTasks) {
mSysUiState.setFlag(SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE, hasFreeformTasks)
- .commitUpdate(DEFAULT_DISPLAY);
+ .commitUpdate(mDisplayTracker.getDefaultDisplayId());
}
}, mSysUiMainExecutor);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 00b2fbe..b9c23d4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -15,7 +15,6 @@
*/
package com.android.keyguard
-import com.android.systemui.statusbar.CommandQueue
import android.content.BroadcastReceiver
import android.testing.AndroidTestingRunner
import android.view.View
@@ -34,6 +33,7 @@
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.mockito.any
@@ -41,8 +41,6 @@
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
-import java.util.TimeZone
-import java.util.concurrent.Executor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.yield
@@ -57,8 +55,10 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import java.util.*
+import java.util.concurrent.Executor
+import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
index 01365b4..1a365ef 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardDisplayManagerTest.java
@@ -25,9 +25,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -39,6 +37,7 @@
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.navigationbar.NavigationBarController;
+import com.android.systemui.settings.FakeDisplayTracker;
import org.junit.Before;
import org.junit.Test;
@@ -58,12 +57,12 @@
@Mock
private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
@Mock
- private DisplayManager mDisplayManager;
- @Mock
private KeyguardDisplayManager.KeyguardPresentation mKeyguardPresentation;
+ private Executor mMainExecutor = Runnable::run;
private Executor mBackgroundExecutor = Runnable::run;
private KeyguardDisplayManager mManager;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
// The default and secondary displays are both in the default group
private Display mDefaultDisplay;
@@ -75,9 +74,9 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
mManager = spy(new KeyguardDisplayManager(mContext, () -> mNavigationBarController,
- mKeyguardStatusViewComponentFactory, mBackgroundExecutor));
+ mKeyguardStatusViewComponentFactory, mDisplayTracker, mMainExecutor,
+ mBackgroundExecutor));
doReturn(mKeyguardPresentation).when(mManager).createPresentation(any());
mDefaultDisplay = new Display(DisplayManagerGlobal.getInstance(), Display.DEFAULT_DISPLAY,
@@ -96,23 +95,21 @@
@Test
public void testShow_defaultDisplayOnly() {
- when(mDisplayManager.getDisplays()).thenReturn(new Display[]{mDefaultDisplay});
+ mDisplayTracker.setAllDisplays(new Display[]{mDefaultDisplay});
mManager.show();
verify(mManager, never()).createPresentation(any());
}
@Test
public void testShow_includeSecondaryDisplay() {
- when(mDisplayManager.getDisplays()).thenReturn(
- new Display[]{mDefaultDisplay, mSecondaryDisplay});
+ mDisplayTracker.setAllDisplays(new Display[]{mDefaultDisplay, mSecondaryDisplay});
mManager.show();
verify(mManager, times(1)).createPresentation(eq(mSecondaryDisplay));
}
@Test
public void testShow_includeAlwaysUnlockedDisplay() {
- when(mDisplayManager.getDisplays()).thenReturn(
- new Display[]{mDefaultDisplay, mAlwaysUnlockedDisplay});
+ mDisplayTracker.setAllDisplays(new Display[]{mDefaultDisplay, mAlwaysUnlockedDisplay});
mManager.show();
verify(mManager, never()).createPresentation(any());
@@ -120,9 +117,8 @@
@Test
public void testShow_includeSecondaryAndAlwaysUnlockedDisplays() {
- when(mDisplayManager.getDisplays()).thenReturn(
+ mDisplayTracker.setAllDisplays(
new Display[]{mDefaultDisplay, mSecondaryDisplay, mAlwaysUnlockedDisplay});
-
mManager.show();
verify(mManager, times(1)).createPresentation(eq(mSecondaryDisplay));
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
index 06082b6..68dc6c0 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java
@@ -29,6 +29,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
@@ -52,6 +53,7 @@
private ConfigurationController mConfigurationController;
@Mock
private ActivityStarter mActivityStarter;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private DumpManager mDumpManager = new DumpManager();
private KeyguardSliceViewController mController;
@@ -63,7 +65,7 @@
when(mView.getContext()).thenReturn(mContext);
mController = new KeyguardSliceViewController(
mView, mActivityStarter, mConfigurationController,
- mTunerService, mDumpManager);
+ mTunerService, mDumpManager, mDisplayTracker);
mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 86cd022..d1650b7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -17,7 +17,6 @@
package com.android.keyguard;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_POWER_BUTTON;
@@ -41,7 +40,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -237,8 +235,6 @@
@Mock
private UiEventLogger mUiEventLogger;
@Mock
- private PowerManager mPowerManager;
- @Mock
private GlobalSettings mGlobalSettings;
private FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
@Mock
@@ -858,6 +854,32 @@
}
@Test
+ public void faceUnlockDoesNotRunWhenDeviceIsGoingToSleepWithAssistantVisible() {
+ mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
+ mKeyguardUpdateMonitor.setAssistantVisible(true);
+
+ verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+ mTestableLooper.processAllMessages();
+ clearInvocations(mFaceManager);
+
+ // Device going to sleep while assistant is visible
+ mKeyguardUpdateMonitor.handleStartedGoingToSleep(0);
+ mKeyguardUpdateMonitor.handleFinishedGoingToSleep(0);
+ mTestableLooper.moveTimeForward(DEFAULT_CANCEL_SIGNAL_TIMEOUT);
+ mTestableLooper.processAllMessages();
+
+ mKeyguardUpdateMonitor.handleKeyguardReset();
+
+ assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isFalse();
+ verify(mFaceManager, never()).authenticate(any(),
+ any(),
+ any(),
+ any(),
+ anyInt(),
+ anyBoolean());
+ }
+
+ @Test
public void testIgnoresAuth_whenTrustAgentOnKeyguard_withoutBypass() {
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
@@ -1884,28 +1906,6 @@
}
@Test
- public void testFingerAcquired_wakesUpPowerManager() {
- cleanupKeyguardUpdateMonitor();
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.kg_wake_on_acquire_start, true);
- mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
- fingerprintAcquireStart();
-
- verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
- }
-
- @Test
- public void testFingerAcquired_doesNotWakeUpPowerManager() {
- cleanupKeyguardUpdateMonitor();
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.kg_wake_on_acquire_start, false);
- mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
- fingerprintAcquireStart();
-
- verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
- }
-
- @Test
public void testDreamingStopped_faceDoesNotRun() {
mKeyguardUpdateMonitor.dispatchDreamingStopped();
mTestableLooper.processAllMessages();
@@ -2386,11 +2386,6 @@
.onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
}
- private void fingerprintAcquireStart() {
- mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
- .onAuthenticationAcquired(FINGERPRINT_ACQUIRED_START);
- }
-
private void deviceInPostureStateOpened() {
mKeyguardUpdateMonitor.mPostureCallback.onPostureChanged(DEVICE_POSTURE_OPENED);
}
@@ -2537,7 +2532,7 @@
mAuthController, mTelephonyListenerManager,
mInteractionJankMonitor, mLatencyTracker, mActiveUnlockConfig,
mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker,
- mPowerManager, mTrustManager, mSubscriptionManager, mUserManager,
+ mTrustManager, mSubscriptionManager, mUserManager,
mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
mFaceWakeUpTriggersConfig, mDevicePostureController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 0627fc6..e918c1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -89,6 +89,7 @@
import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
import com.android.systemui.decor.RoundedCornerResDelegate;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.tuner.TunerService;
@@ -117,6 +118,7 @@
private DisplayManager mDisplayManager;
private SecureSettings mSecureSettings;
private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private FakeThreadFactory mThreadFactory;
private ArrayList<DecorProvider> mPrivacyDecorProviders;
private ArrayList<DecorProvider> mFaceScanningProviders;
@@ -220,7 +222,7 @@
mExecutor));
mScreenDecorations = spy(new ScreenDecorations(mContext, mExecutor, mSecureSettings,
- mTunerService, mUserTracker, mDotViewController, mThreadFactory,
+ mTunerService, mUserTracker, mDisplayTracker, mDotViewController, mThreadFactory,
mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory) {
@Override
public void start() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
index 58b4af4..da419d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -39,6 +39,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
@@ -76,6 +77,7 @@
private IWindowMagnificationConnection mIWindowMagnificationConnection;
private WindowMagnification mWindowMagnification;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@Before
public void setUp() throws Exception {
@@ -88,7 +90,7 @@
any(IWindowMagnificationConnection.class));
mWindowMagnification = new WindowMagnification(getContext(),
getContext().getMainThreadHandler(), mCommandQueue,
- mModeSwitchesController, mSysUiState, mOverviewProxyService);
+ mModeSwitchesController, mSysUiState, mOverviewProxyService, mDisplayTracker);
mWindowMagnification.mMagnificationControllerSupplier = new FakeControllerSupplier(
mContext.getSystemService(DisplayManager.class));
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 cdf3f65..f4505f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -78,6 +78,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.model.SysUiState;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.util.leak.ReferenceTestUtils;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.utils.os.FakeHandler;
@@ -120,11 +121,12 @@
private Handler mHandler;
private TestableWindowManager mWindowManager;
- private SysUiState mSysUiState = new SysUiState();
+ private SysUiState mSysUiState;
private Resources mResources;
private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
private WindowMagnificationController mWindowMagnificationController;
private Instrumentation mInstrumentation;
+ private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private final ValueAnimator mValueAnimator = ValueAnimator.ofFloat(0, 1.0f).setDuration(0);
@Before
@@ -143,6 +145,7 @@
return null;
}).when(mSfVsyncFrameProvider).postFrameCallback(
any(FrameCallback.class));
+ mSysUiState = new SysUiState(mDisplayTracker);
mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class));
when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).then(
returnsSecondArg());
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 ccf2f8b..f75dc03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -45,6 +45,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
@@ -74,6 +75,8 @@
private CommandQueue mCommandQueue;
private WindowMagnification mWindowMagnification;
private OverviewProxyListener mOverviewProxyListener;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -87,10 +90,10 @@
when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
- mCommandQueue = new CommandQueue(getContext());
+ mCommandQueue = new CommandQueue(getContext(), new FakeDisplayTracker(getContext()));
mWindowMagnification = new WindowMagnification(getContext(),
getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController,
- mSysUiState, mOverviewProxyService);
+ mSysUiState, mOverviewProxyService, mDisplayTracker);
mWindowMagnification.start();
final ArgumentCaptor<OverviewProxyListener> listenerArgumentCaptor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index a61cd23..578e1d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -15,6 +15,7 @@
import android.view.RemoteAnimationTarget
import android.view.SurfaceControl
import android.view.ViewGroup
+import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -26,6 +27,7 @@
import junit.framework.AssertionFailedError
import kotlin.concurrent.thread
import org.junit.After
+import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -195,6 +197,13 @@
verify(controller).onLaunchAnimationStart(anyBoolean())
}
+ @Test
+ fun creatingControllerFromNormalViewThrows() {
+ assertThrows(IllegalArgumentException::class.java) {
+ ActivityLaunchAnimator.Controller.fromView(FrameLayout(mContext))
+ }
+ }
+
private fun fakeWindow(): RemoteAnimationTarget {
val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
val taskInfo = ActivityManager.RunningTaskInfo()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
index cac4a0e..1e62fd23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -26,6 +26,7 @@
import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -260,6 +261,13 @@
assertThat(touchSurface.visibility).isEqualTo(View.GONE)
}
+ @Test
+ fun creatingControllerFromNormalViewThrows() {
+ assertThrows(IllegalArgumentException::class.java) {
+ DialogLaunchAnimator.Controller.fromView(FrameLayout(mContext))
+ }
+ }
+
private fun createAndShowDialog(
animator: DialogLaunchAnimator = dialogLaunchAnimator,
): TestDialog {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
index 3696ec5..0798d73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
@@ -16,58 +16,34 @@
package com.android.systemui.animation
-import android.graphics.drawable.Drawable
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
-import android.view.View
-import android.view.ViewGroup
-import android.view.ViewParent
+import android.widget.FrameLayout
import androidx.test.filters.SmallTest
-import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.SysuiTestCase
-import org.junit.Before
+import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mock
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class GhostedViewLaunchAnimatorControllerTest : SysuiTestCase() {
- @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
- @Mock lateinit var view: View
- @Mock lateinit var rootView: ViewGroup
- @Mock lateinit var viewParent: ViewParent
- @Mock lateinit var drawable: Drawable
- lateinit var controller: GhostedViewLaunchAnimatorController
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- whenever(view.rootView).thenReturn(rootView)
- whenever(view.background).thenReturn(drawable)
- whenever(view.height).thenReturn(0)
- whenever(view.width).thenReturn(0)
- whenever(view.parent).thenReturn(viewParent)
- whenever(view.visibility).thenReturn(View.VISIBLE)
- whenever(view.invalidate()).then { /* NO-OP */ }
- whenever(view.getLocationOnScreen(any())).then { /* NO-OP */ }
- whenever(interactionJankMonitor.begin(any(), anyInt())).thenReturn(true)
- whenever(interactionJankMonitor.end(anyInt())).thenReturn(true)
- controller = GhostedViewLaunchAnimatorController(view, 0, interactionJankMonitor)
- }
-
@Test
fun animatingOrphanViewDoesNotCrash() {
val state = LaunchAnimator.State(top = 0, bottom = 0, left = 0, right = 0)
+ val controller = GhostedViewLaunchAnimatorController(LaunchableFrameLayout(mContext))
controller.onIntentStarted(willAnimate = true)
controller.onLaunchAnimationStart(isExpandingFullyAbove = true)
controller.onLaunchAnimationProgress(state, progress = 0f, linearProgress = 0f)
controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
}
+
+ @Test
+ fun creatingControllerFromNormalViewThrows() {
+ assertThrows(IllegalArgumentException::class.java) {
+ GhostedViewLaunchAnimatorController(FrameLayout(mContext))
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index b92c5d0..fd931b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -51,14 +51,24 @@
import android.view.WindowMetrics
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.ViewMediatorCallback
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestableContext
import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags.MODERN_ALTERNATE_BOUNCER
+import com.android.systemui.keyguard.data.repository.FakeBiometricRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestCoroutineScope
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -101,6 +111,9 @@
@Captor lateinit var overlayCaptor: ArgumentCaptor<View>
@Captor lateinit var overlayViewParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
+ private lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private val featureFlags = FakeFeatureFlags()
private val executor = FakeExecutor(FakeSystemClock())
private lateinit var overlayController: ISidefpsController
private lateinit var sideFpsController: SideFpsController
@@ -121,6 +134,24 @@
@Before
fun setup() {
+ featureFlags.set(MODERN_ALTERNATE_BOUNCER, true)
+ keyguardBouncerRepository =
+ KeyguardBouncerRepository(
+ mock(ViewMediatorCallback::class.java),
+ FakeSystemClock(),
+ TestCoroutineScope(),
+ mock(TableLogBuffer::class.java),
+ )
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ keyguardBouncerRepository,
+ FakeBiometricRepository(),
+ FakeDeviceEntryFingerprintAuthRepository(),
+ FakeSystemClock(),
+ mock(KeyguardUpdateMonitor::class.java),
+ featureFlags,
+ )
+
context.addMockSystemService(DisplayManager::class.java, displayManager)
context.addMockSystemService(WindowManager::class.java, windowManager)
@@ -217,7 +248,10 @@
displayManager,
executor,
handler,
- dumpManager
+ alternateBouncerInteractor,
+ TestCoroutineScope(),
+ featureFlags,
+ dumpManager,
)
overlayController =
@@ -507,6 +541,26 @@
private fun verifySfpsIndicatorVisibilityOnTaskbarUpdate(sfpsViewVisible: Boolean) {
sideFpsController.overlayOffsets = sensorLocation
+ }
+
+ fun alternateBouncerVisibility_showAndHideSideFpsUI() = testWithDisplay {
+ // WHEN alternate bouncer is visible
+ keyguardBouncerRepository.setAlternateVisible(true)
+ executor.runAllReady()
+
+ // THEN side fps shows UI
+ verify(windowManager).addView(any(), any())
+ verify(windowManager, never()).removeView(any())
+
+ // WHEN alternate bouncer is no longer visible
+ keyguardBouncerRepository.setAlternateVisible(false)
+ executor.runAllReady()
+
+ // THEN side fps UI is hidden
+ verify(windowManager).removeView(any())
+ }
+
+ private fun hidesWithTaskbar(visible: Boolean) {
overlayController.show(SENSOR_ID, REASON_UNKNOWN)
executor.runAllReady()
@@ -515,7 +569,7 @@
verify(windowManager).addView(any(), any())
verify(windowManager, never()).removeView(any())
- verify(sideFpsView).visibility = if (sfpsViewVisible) View.VISIBLE else View.GONE
+ verify(sideFpsView).visibility = if (visible) View.VISIBLE else View.GONE
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
index 9c32c38..498cc29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java
@@ -37,7 +37,6 @@
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
@@ -71,7 +70,6 @@
protected @Mock SystemUIDialogManager mDialogManager;
protected @Mock UdfpsController mUdfpsController;
protected @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
- protected @Mock KeyguardBouncer mBouncer;
protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
protected @Mock AlternateBouncerInteractor mAlternateBouncerInteractor;
@@ -152,8 +150,6 @@
mFeatureFlags.set(Flags.MODERN_BOUNCER, useModernBouncer);
mFeatureFlags.set(Flags.MODERN_ALTERNATE_BOUNCER, useModernBouncer);
mFeatureFlags.set(Flags.UDFPS_NEW_TOUCH_DETECTION, useExpandedOverlay);
- when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn(
- useModernBouncer ? null : mBouncer);
UdfpsKeyguardViewController controller = new UdfpsKeyguardViewController(
mView,
mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 7715f7f..f437a8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -32,24 +32,17 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.statusbar.StatusBarState;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
- private @Captor ArgumentCaptor<PrimaryBouncerExpansionCallback>
- mBouncerExpansionCallbackCaptor;
- private PrimaryBouncerExpansionCallback mBouncerExpansionCallback;
-
@Override
public UdfpsKeyguardViewController createUdfpsKeyguardViewController() {
return createUdfpsKeyguardViewController(/* useModernBouncer */ false,
@@ -62,11 +55,9 @@
captureStatusBarStateListeners();
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
- captureBouncerExpansionCallback();
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
when(mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()).thenReturn(true);
- mBouncerExpansionCallback.onVisibilityChanged(true);
-
+ when(mView.getUnpausedAlpha()).thenReturn(0);
assertTrue(mController.shouldPauseAuth());
}
@@ -304,11 +295,6 @@
verify(mView, atLeastOnce()).setPauseAuth(false);
}
- private void captureBouncerExpansionCallback() {
- verify(mBouncer).addBouncerExpansionCallback(mBouncerExpansionCallbackCaptor.capture());
- mBouncerExpansionCallback = mBouncerExpansionCallbackCaptor.getValue();
- }
-
@Test
// TODO(b/259264861): Tracking Bug
public void testUdfpsExpandedOverlayOn() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 9060922..81a6bc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.BouncerView
import com.android.systemui.keyguard.data.repository.BiometricRepository
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
@@ -91,6 +92,7 @@
AlternateBouncerInteractor(
keyguardBouncerRepository,
mock(BiometricRepository::class.java),
+ mock(DeviceEntryFingerprintAuthRepository::class.java),
mock(SystemClock::class.java),
mock(KeyguardUpdateMonitor::class.java),
mock(FeatureFlags::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
index bdd496e..71c335e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
@@ -16,8 +16,6 @@
package com.android.systemui.clipboardoverlay;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED;
-
import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE;
import static org.junit.Assert.assertEquals;
@@ -33,7 +31,6 @@
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.os.PersistableBundle;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import androidx.test.filters.SmallTest;
@@ -41,9 +38,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.util.DeviceConfigProxyFake;
import org.junit.Before;
import org.junit.Test;
@@ -63,18 +57,11 @@
@Mock
private ClipboardManager mClipboardManager;
@Mock
- private ClipboardOverlayControllerLegacyFactory mClipboardOverlayControllerLegacyFactory;
- @Mock
- private ClipboardOverlayControllerLegacy mOverlayControllerLegacy;
- @Mock
private ClipboardOverlayController mOverlayController;
@Mock
private ClipboardToast mClipboardToast;
@Mock
private UiEventLogger mUiEventLogger;
- @Mock
- private FeatureFlags mFeatureFlags;
- private DeviceConfigProxyFake mDeviceConfigProxy;
private ClipData mSampleClipData;
private String mSampleSource = "Example source";
@@ -97,8 +84,6 @@
mOverlayControllerProvider = () -> mOverlayController;
MockitoAnnotations.initMocks(this);
- when(mClipboardOverlayControllerLegacyFactory.create(any()))
- .thenReturn(mOverlayControllerLegacy);
when(mClipboardManager.hasPrimaryClip()).thenReturn(true);
Settings.Secure.putInt(
mContext.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 1);
@@ -108,26 +93,13 @@
when(mClipboardManager.getPrimaryClip()).thenReturn(mSampleClipData);
when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource);
- mDeviceConfigProxy = new DeviceConfigProxyFake();
-
- mClipboardListener = new ClipboardListener(getContext(), mDeviceConfigProxy,
- mOverlayControllerProvider, mClipboardOverlayControllerLegacyFactory,
- mClipboardToast, mClipboardManager, mUiEventLogger, mFeatureFlags);
+ mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider,
+ mClipboardToast, mClipboardManager, mUiEventLogger);
}
- @Test
- public void test_disabled() {
- mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
- "false", false);
- mClipboardListener.start();
- verifyZeroInteractions(mClipboardManager);
- verifyZeroInteractions(mUiEventLogger);
- }
@Test
- public void test_enabled() {
- mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
- "true", false);
+ public void test_initialization() {
mClipboardListener.start();
verify(mClipboardManager).addPrimaryClipChangedListener(any());
verifyZeroInteractions(mUiEventLogger);
@@ -135,45 +107,6 @@
@Test
public void test_consecutiveCopies() {
- when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(false);
-
- mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
- "true", false);
- mClipboardListener.start();
- mClipboardListener.onPrimaryClipChanged();
-
- verify(mClipboardOverlayControllerLegacyFactory).create(any());
-
- verify(mOverlayControllerLegacy).setClipData(
- mClipDataCaptor.capture(), mStringCaptor.capture());
-
- assertEquals(mSampleClipData, mClipDataCaptor.getValue());
- assertEquals(mSampleSource, mStringCaptor.getValue());
-
- verify(mOverlayControllerLegacy).setOnSessionCompleteListener(mRunnableCaptor.capture());
-
- // Should clear the overlay controller
- mRunnableCaptor.getValue().run();
-
- mClipboardListener.onPrimaryClipChanged();
-
- verify(mClipboardOverlayControllerLegacyFactory, times(2)).create(any());
-
- // Not calling the runnable here, just change the clip again and verify that the overlay is
- // NOT recreated.
-
- mClipboardListener.onPrimaryClipChanged();
-
- verify(mClipboardOverlayControllerLegacyFactory, times(2)).create(any());
- verifyZeroInteractions(mOverlayControllerProvider);
- }
-
- @Test
- public void test_consecutiveCopies_new() {
- when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(true);
-
- mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED,
- "true", false);
mClipboardListener.start();
mClipboardListener.onPrimaryClipChanged();
@@ -200,7 +133,6 @@
mClipboardListener.onPrimaryClipChanged();
verify(mOverlayControllerProvider, times(2)).get();
- verifyZeroInteractions(mClipboardOverlayControllerLegacyFactory);
}
@Test
@@ -231,23 +163,6 @@
@Test
public void test_logging_enterAndReenter() {
- when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(false);
-
- mClipboardListener.start();
-
- mClipboardListener.onPrimaryClipChanged();
- mClipboardListener.onPrimaryClipChanged();
-
- verify(mUiEventLogger, times(1)).log(
- ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED, 0, mSampleSource);
- verify(mUiEventLogger, times(1)).log(
- ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED, 0, mSampleSource);
- }
-
- @Test
- public void test_logging_enterAndReenter_new() {
- when(mFeatureFlags.isEnabled(Flags.CLIPBOARD_OVERLAY_REFACTOR)).thenReturn(true);
-
mClipboardListener.start();
mClipboardListener.onPrimaryClipChanged();
@@ -271,6 +186,5 @@
ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource);
verify(mClipboardToast, times(1)).showCopiedToast();
verifyZeroInteractions(mOverlayControllerProvider);
- verifyZeroInteractions(mClipboardOverlayControllerLegacyFactory);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index b4e85c0..ca5b7af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -47,6 +47,7 @@
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.screenshot.TimeoutHandler;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -81,6 +82,7 @@
private ClipboardOverlayUtils mClipboardUtils;
@Mock
private UiEventLogger mUiEventLogger;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@Mock
@@ -116,7 +118,8 @@
mFeatureFlags,
mClipboardUtils,
mExecutor,
- mUiEventLogger);
+ mUiEventLogger,
+ mDisplayTracker);
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
mCallbacks = mOverlayCallbacksCaptor.getValue();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
new file mode 100644
index 0000000..fe352fd
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/common/ui/view/LongPressHandlingViewInteractionHandlerTest.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.common.ui.view
+
+import android.view.ViewConfiguration
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.view.LongPressHandlingViewInteractionHandler.MotionEventModel
+import com.android.systemui.common.ui.view.LongPressHandlingViewInteractionHandler.MotionEventModel.Down
+import com.android.systemui.common.ui.view.LongPressHandlingViewInteractionHandler.MotionEventModel.Move
+import com.android.systemui.common.ui.view.LongPressHandlingViewInteractionHandler.MotionEventModel.Up
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+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.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class LongPressHandlingViewInteractionHandlerTest : SysuiTestCase() {
+
+ @Mock private lateinit var postDelayed: (Runnable, Long) -> DisposableHandle
+ @Mock private lateinit var onLongPressDetected: (Int, Int) -> Unit
+ @Mock private lateinit var onSingleTapDetected: () -> Unit
+
+ private lateinit var underTest: LongPressHandlingViewInteractionHandler
+
+ private var isAttachedToWindow: Boolean = true
+ private var delayedRunnable: Runnable? = null
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(postDelayed.invoke(any(), any())).thenAnswer { invocation ->
+ delayedRunnable = invocation.arguments[0] as Runnable
+ DisposableHandle { delayedRunnable = null }
+ }
+
+ underTest =
+ LongPressHandlingViewInteractionHandler(
+ postDelayed = postDelayed,
+ isAttachedToWindow = { isAttachedToWindow },
+ onLongPressDetected = onLongPressDetected,
+ onSingleTapDetected = onSingleTapDetected,
+ )
+ underTest.isLongPressHandlingEnabled = true
+ }
+
+ @Test
+ fun `long-press`() = runTest {
+ val downX = 123
+ val downY = 456
+ dispatchTouchEvents(
+ Down(
+ x = downX,
+ y = downY,
+ ),
+ Move(
+ distanceMoved = ViewConfiguration.getTouchSlop() - 0.1f,
+ ),
+ )
+ delayedRunnable?.run()
+
+ verify(onLongPressDetected).invoke(downX, downY)
+ verify(onSingleTapDetected, never()).invoke()
+ }
+
+ @Test
+ fun `long-press but feature not enabled`() = runTest {
+ underTest.isLongPressHandlingEnabled = false
+ dispatchTouchEvents(
+ Down(
+ x = 123,
+ y = 456,
+ ),
+ )
+
+ assertThat(delayedRunnable).isNull()
+ verify(onLongPressDetected, never()).invoke(any(), any())
+ verify(onSingleTapDetected, never()).invoke()
+ }
+
+ @Test
+ fun `long-press but view not attached`() = runTest {
+ isAttachedToWindow = false
+ dispatchTouchEvents(
+ Down(
+ x = 123,
+ y = 456,
+ ),
+ )
+ delayedRunnable?.run()
+
+ verify(onLongPressDetected, never()).invoke(any(), any())
+ verify(onSingleTapDetected, never()).invoke()
+ }
+
+ @Test
+ fun `dragged too far to be considered a long-press`() = runTest {
+ dispatchTouchEvents(
+ Down(
+ x = 123,
+ y = 456,
+ ),
+ Move(
+ distanceMoved = ViewConfiguration.getTouchSlop() + 0.1f,
+ ),
+ )
+
+ assertThat(delayedRunnable).isNull()
+ verify(onLongPressDetected, never()).invoke(any(), any())
+ verify(onSingleTapDetected, never()).invoke()
+ }
+
+ @Test
+ fun `held down too briefly to be considered a long-press`() = runTest {
+ dispatchTouchEvents(
+ Down(
+ x = 123,
+ y = 456,
+ ),
+ Up(
+ distanceMoved = ViewConfiguration.getTouchSlop().toFloat(),
+ gestureDuration = ViewConfiguration.getLongPressTimeout() - 1L,
+ ),
+ )
+
+ assertThat(delayedRunnable).isNull()
+ verify(onLongPressDetected, never()).invoke(any(), any())
+ verify(onSingleTapDetected).invoke()
+ }
+
+ private fun dispatchTouchEvents(
+ vararg models: MotionEventModel,
+ ) {
+ models.forEach { model -> underTest.onTouchEvent(model) }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
index ed40c90..85f9961 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -20,6 +20,7 @@
import android.content.ComponentName
import android.content.Context
import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
import android.content.pm.ServiceInfo
import android.os.UserHandle
import android.service.controls.ControlsProviderService
@@ -95,6 +96,7 @@
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
@Mock lateinit var featureFlags: FeatureFlags
+ @Mock lateinit var packageManager: PackageManager
val sharedPreferences = FakeSharedPreferences()
lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
@@ -124,6 +126,7 @@
ControlsUiControllerImpl(
Lazy { controlsController },
context,
+ packageManager,
uiExecutor,
bgExecutor,
Lazy { controlsListingController },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
new file mode 100644
index 0000000..dbaf94f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/OverflowMenuAdapterTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls.ui
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class OverflowMenuAdapterTest : SysuiTestCase() {
+
+ @Test
+ fun testGetItemId() {
+ val ids = listOf(27L, 73L)
+ val labels = listOf("first", "second")
+ val adapter =
+ OverflowMenuAdapter(
+ context,
+ layoutId = 0,
+ labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
+ ) { true }
+
+ ids.forEachIndexed { index, id -> assertThat(adapter.getItemId(index)).isEqualTo(id) }
+ }
+
+ @Test
+ fun testCheckEnabled() {
+ val ids = listOf(27L, 73L)
+ val labels = listOf("first", "second")
+ val adapter =
+ OverflowMenuAdapter(
+ context,
+ layoutId = 0,
+ labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
+ ) { position -> position == 0 }
+
+ assertThat(adapter.isEnabled(0)).isTrue()
+ assertThat(adapter.isEnabled(1)).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index ff883eb..6b095ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -36,11 +36,10 @@
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
+import com.android.systemui.dreams.touch.scrim.BouncerlessScrimController;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
import com.android.systemui.statusbar.BlurUtils;
-import com.android.systemui.statusbar.phone.KeyguardBouncer;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import org.junit.Before;
import org.junit.Test;
@@ -81,12 +80,6 @@
BlurUtils mBlurUtils;
@Mock
- StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-
- @Mock
- KeyguardBouncer mBouncer;
-
- @Mock
ViewRootImpl mViewRoot;
@Mock
@@ -96,6 +89,9 @@
DreamOverlayAnimationsController mAnimationsController;
@Mock
+ BouncerlessScrimController mBouncerlessScrimController;
+
+ @Mock
DreamOverlayStateController mStateController;
DreamOverlayContainerViewController mController;
@@ -106,7 +102,6 @@
when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
- when(mStatusBarKeyguardViewManager.getPrimaryBouncer()).thenReturn(mBouncer);
when(mDreamOverlayContainerView.getViewRootImpl()).thenReturn(mViewRoot);
mController = new DreamOverlayContainerViewController(
@@ -114,7 +109,6 @@
mComplicationHostViewController,
mDreamOverlayContentView,
mDreamOverlayStatusBarViewController,
- mStatusBarKeyguardViewManager,
mBlurUtils,
mHandler,
mResources,
@@ -123,7 +117,8 @@
MILLIS_UNTIL_FULL_JITTER,
mPrimaryBouncerCallbackInteractor,
mAnimationsController,
- mStateController);
+ mStateController,
+ mBouncerlessScrimController);
}
@Test
@@ -170,7 +165,8 @@
final ArgumentCaptor<PrimaryBouncerExpansionCallback> bouncerExpansionCaptor =
ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
mController.onViewAttached();
- verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
+ verify(mPrimaryBouncerCallbackInteractor).addBouncerExpansionCallback(
+ bouncerExpansionCaptor.capture());
bouncerExpansionCaptor.getValue().onExpansionChanged(0.5f);
verify(mBlurUtils, never()).applyBlur(eq(mViewRoot), anyInt(), eq(false));
@@ -181,7 +177,8 @@
final ArgumentCaptor<PrimaryBouncerExpansionCallback> bouncerExpansionCaptor =
ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
mController.onViewAttached();
- verify(mBouncer).addBouncerExpansionCallback(bouncerExpansionCaptor.capture());
+ verify(mPrimaryBouncerCallbackInteractor).addBouncerExpansionCallback(
+ bouncerExpansionCaptor.capture());
final float blurRadius = 1337f;
when(mBlurUtils.blurRadiusOfRatio(anyFloat())).thenReturn(blurRadius);
@@ -217,6 +214,27 @@
}
@Test
+ public void testSkipEntryAnimationsWhenExitingLowLight() {
+ ArgumentCaptor<DreamOverlayStateController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
+ when(mStateController.isLowLightActive()).thenReturn(false);
+
+ // Call onInit so that the callback is added.
+ mController.onInit();
+ verify(mStateController).addCallback(callbackCaptor.capture());
+
+ // Send the signal that low light is exiting
+ callbackCaptor.getValue().onExitLowLight();
+
+ // View is attached to trigger animations.
+ mController.onViewAttached();
+
+ // Entry animations should be started then immediately ended to skip to the end.
+ verify(mAnimationsController).startEntryAnimations();
+ verify(mAnimationsController).endAnimations();
+ }
+
+ @Test
public void testCancelDreamEntryAnimationsOnDetached() {
mController.onViewAttached();
mController.onViewDetached();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index ee989d1..b7d0f29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -251,6 +251,30 @@
}
@Test
+ public void testNotifyLowLightExit() {
+ final DreamOverlayStateController stateController =
+ new DreamOverlayStateController(mExecutor, true);
+
+ stateController.addCallback(mCallback);
+ mExecutor.runAllReady();
+ assertThat(stateController.isLowLightActive()).isFalse();
+
+ // Turn low light on then off to trigger the exiting callback.
+ stateController.setLowLightActive(true);
+ stateController.setLowLightActive(false);
+
+ // Callback was only called once, when
+ mExecutor.runAllReady();
+ verify(mCallback, times(1)).onExitLowLight();
+ assertThat(stateController.isLowLightActive()).isFalse();
+
+ // Set with false again, which should not cause the callback to trigger again.
+ stateController.setLowLightActive(false);
+ mExecutor.runAllReady();
+ verify(mCallback, times(1)).onExitLowLight();
+ }
+
+ @Test
public void testNotifyEntryAnimationsFinishedChanged() {
final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor, true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index 89c7280..a4cf15c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -31,13 +31,13 @@
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.view.View;
-import android.widget.ImageView;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.common.ui.view.LaunchableImageView;
import com.android.systemui.controls.ControlsServiceInfo;
import com.android.systemui.controls.controller.ControlsController;
import com.android.systemui.controls.controller.StructureInfo;
@@ -90,7 +90,7 @@
private View mView;
@Mock
- private ImageView mHomeControlsView;
+ private LaunchableImageView mHomeControlsView;
@Mock
private ActivityStarter mActivityStarter;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
new file mode 100644
index 0000000..19347c7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/conditions/DreamConditionTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.conditions;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.condition.Condition;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DreamConditionTest extends SysuiTestCase {
+ @Mock
+ Context mContext;
+
+ @Mock
+ Condition.Callback mCallback;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ /**
+ * Ensure a dreaming state immediately triggers the condition.
+ */
+ @Test
+ public void testInitialState() {
+ final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
+ when(mContext.registerReceiver(any(), any())).thenReturn(intent);
+ final DreamCondition condition = new DreamCondition(mContext);
+ condition.addCallback(mCallback);
+ condition.start();
+
+ verify(mCallback).onConditionChanged(eq(condition));
+ assertThat(condition.isConditionMet()).isTrue();
+ }
+
+ /**
+ * Ensure that changing dream state triggers condition.
+ */
+ @Test
+ public void testChange() {
+ final Intent intent = new Intent(Intent.ACTION_DREAMING_STARTED);
+ final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ when(mContext.registerReceiver(receiverCaptor.capture(), any())).thenReturn(intent);
+ final DreamCondition condition = new DreamCondition(mContext);
+ condition.addCallback(mCallback);
+ condition.start();
+ clearInvocations(mCallback);
+ receiverCaptor.getValue().onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
+ verify(mCallback).onConditionChanged(eq(condition));
+ assertThat(condition.isConditionMet()).isFalse();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index f64179d..3a168d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -41,12 +41,13 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.touch.scrim.ScrimController;
+import com.android.systemui.dreams.touch.scrim.ScrimManager;
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shared.system.InputChannelCompat;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
@@ -63,10 +64,13 @@
@RunWith(AndroidTestingRunner.class)
public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@Mock
- StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ CentralSurfaces mCentralSurfaces;
@Mock
- CentralSurfaces mCentralSurfaces;
+ ScrimManager mScrimManager;
+
+ @Mock
+ ScrimController mScrimController;
@Mock
NotificationShadeWindowController mNotificationShadeWindowController;
@@ -111,7 +115,7 @@
MockitoAnnotations.initMocks(this);
mTouchHandler = new BouncerSwipeTouchHandler(
mDisplayMetrics,
- mStatusBarKeyguardViewManager,
+ mScrimManager,
Optional.of(mCentralSurfaces),
mNotificationShadeWindowController,
mValueAnimatorCreator,
@@ -121,6 +125,7 @@
TOUCH_REGION,
mUiEventLogger);
+ when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
when(mCentralSurfaces.isBouncerShowing()).thenReturn(false);
when(mCentralSurfaces.getDisplayHeight()).thenReturn((float) SCREEN_HEIGHT_PX);
when(mValueAnimatorCreator.create(anyFloat(), anyFloat())).thenReturn(mValueAnimator);
@@ -193,7 +198,7 @@
assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
.isTrue();
- verify(mStatusBarKeyguardViewManager, never()).onPanelExpansionChanged(any());
+ verify(mScrimController, never()).expand(any());
}
/**
@@ -220,7 +225,7 @@
assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
.isTrue();
- verify(mStatusBarKeyguardViewManager, never()).onPanelExpansionChanged(any());
+ verify(mScrimController, never()).expand(any());
}
/**
@@ -274,12 +279,12 @@
final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
0, direction == Direction.UP ? SCREEN_HEIGHT_PX - distanceY : distanceY, 0);
- reset(mStatusBarKeyguardViewManager);
+ reset(mScrimController);
assertThat(gestureListener.onScroll(event1, event2, 0, distanceY))
.isTrue();
// Ensure only called once
- verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(any());
+ verify(mScrimController).expand(any());
final float expansion = isBouncerInitiallyShowing ? percent : 1 - percent;
final float dragDownAmount = event2.getY() - event1.getY();
@@ -288,7 +293,7 @@
ShadeExpansionChangeEvent event =
new ShadeExpansionChangeEvent(
expansion, /* expanded= */ false, /* tracking= */ true, dragDownAmount);
- verify(mStatusBarKeyguardViewManager).onPanelExpansionChanged(event);
+ verify(mScrimController).expand(event);
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
index a807407..178b9cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/DreamOverlayTouchMonitorTest.java
@@ -424,6 +424,32 @@
verify(gestureListener2).onDown(eq(followupEvent));
}
+ @Test
+ public void testOnRemovedCallbackOnStopMonitoring() {
+ final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class);
+ final DreamTouchHandler.TouchSession.Callback callback =
+ Mockito.mock(DreamTouchHandler.TouchSession.Callback.class);
+
+ final Environment environment = new Environment(Stream.of(touchHandler)
+ .collect(Collectors.toCollection(HashSet::new)));
+
+ final InputEvent initialEvent = Mockito.mock(InputEvent.class);
+ environment.publishInputEvent(initialEvent);
+
+ final DreamTouchHandler.TouchSession session = captureSession(touchHandler);
+ session.registerCallback(callback);
+
+ environment.executeAll();
+
+ environment.updateLifecycle(observerOwnerPair -> {
+ observerOwnerPair.first.onPause(observerOwnerPair.second);
+ });
+
+ environment.executeAll();
+
+ verify(callback).onRemoved();
+ }
+
public GestureDetector.OnGestureListener registerGestureListener(DreamTouchHandler handler) {
final GestureDetector.OnGestureListener gestureListener = Mockito.mock(
GestureDetector.OnGestureListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
new file mode 100644
index 0000000..79c535a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch.scrim;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.os.PowerManager;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shade.ShadeExpansionChangeEvent;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class BouncerlessScrimControllerTest extends SysuiTestCase {
+ @Mock
+ BouncerlessScrimController.Callback mCallback;
+
+ @Mock
+ PowerManager mPowerManager;
+
+ private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testWakeupOnSwipeOpen() {
+ final BouncerlessScrimController scrimController =
+ new BouncerlessScrimController(mExecutor, mPowerManager);
+ scrimController.addCallback(mCallback);
+ scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false, 0.0f));
+ mExecutor.runAllReady();
+ verify(mPowerManager).wakeUp(anyLong(), eq(PowerManager.WAKE_REASON_GESTURE), any());
+ verify(mCallback).onWakeup();
+ }
+
+ @Test
+ public void testExpansionPropagation() {
+ final BouncerlessScrimController scrimController =
+ new BouncerlessScrimController(mExecutor, mPowerManager);
+ scrimController.addCallback(mCallback);
+ final ShadeExpansionChangeEvent expansionEvent =
+ new ShadeExpansionChangeEvent(0.5f, false, false, 0.0f);
+ scrimController.expand(expansionEvent);
+ mExecutor.runAllReady();
+ verify(mCallback).onExpansion(eq(expansionEvent));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
new file mode 100644
index 0000000..ac9822d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/scrim/ScrimManagerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch.scrim;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class ScrimManagerTest extends SysuiTestCase {
+ @Mock
+ ScrimController mBouncerlessScrimController;
+
+ @Mock
+ ScrimController mBouncerScrimController;
+
+ @Mock
+ KeyguardStateController mKeyguardStateController;
+
+ @Mock
+ ScrimManager.Callback mCallback;
+
+ private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testControllerSelection() {
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+ final ScrimManager manager = new ScrimManager(mExecutor, mBouncerScrimController,
+ mBouncerlessScrimController, mKeyguardStateController);
+ verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+
+ assertThat(manager.getCurrentController()).isEqualTo(mBouncerScrimController);
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+ callbackCaptor.getValue().onKeyguardShowingChanged();
+ mExecutor.runAllReady();
+ assertThat(manager.getCurrentController()).isEqualTo(mBouncerlessScrimController);
+ }
+
+ @Test
+ public void testCallback() {
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ ArgumentCaptor<KeyguardStateController.Callback> callbackCaptor =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+ final ScrimManager manager = new ScrimManager(mExecutor, mBouncerScrimController,
+ mBouncerlessScrimController, mKeyguardStateController);
+ verify(mKeyguardStateController).addCallback(callbackCaptor.capture());
+
+ manager.addCallback(mCallback);
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
+ callbackCaptor.getValue().onKeyguardShowingChanged();
+ mExecutor.runAllReady();
+ verify(mCallback).onScrimControllerChanged(eq(mBouncerlessScrimController));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
index 77c837b..a2dc1eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/fragments/FragmentServiceTest.kt
@@ -14,6 +14,7 @@
@SmallTest
class FragmentServiceTest : SysuiTestCase() {
private val fragmentCreator = TestFragmentCreator()
+ private val fragmenetHostManagerFactory: FragmentHostManager.Factory = mock()
private val fragmentCreatorFactory = FragmentService.FragmentCreator.Factory { fragmentCreator }
private lateinit var fragmentService: FragmentService
@@ -24,7 +25,13 @@
Looper.prepare()
}
- fragmentService = FragmentService(fragmentCreatorFactory, mock(), DumpManager())
+ fragmentService =
+ FragmentService(
+ fragmentCreatorFactory,
+ fragmenetHostManagerFactory,
+ mock(),
+ DumpManager()
+ )
}
@Test
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 c0af0cb..fb54d6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -62,6 +62,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -184,6 +185,7 @@
mainDispatcher = testDispatcher,
backgroundHandler = backgroundHandler,
)
+ underTest.mainDispatcher = UnconfinedTestDispatcher()
underTest.attachInfoForTesting(
context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index 8da4eae..58cdec4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -19,6 +19,7 @@
import android.app.StatusBarManager
import android.content.Context
+import android.content.pm.PackageManager
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.camera.CameraGestureHelper
@@ -32,7 +33,6 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.Mock
-import org.mockito.Mockito.anyInt
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -43,16 +43,19 @@
@Mock private lateinit var cameraGestureHelper: CameraGestureHelper
@Mock private lateinit var context: Context
+ @Mock private lateinit var packageManager: PackageManager
private lateinit var underTest: CameraQuickAffordanceConfig
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ setLaunchable(true)
underTest =
CameraQuickAffordanceConfig(
context,
+ packageManager,
) {
cameraGestureHelper
}
@@ -86,6 +89,7 @@
}
private fun setLaunchable(isLaunchable: Boolean) {
- whenever(cameraGestureHelper.canCameraGestureBeLaunched(anyInt())).thenReturn(isLaunchable)
+ whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY))
+ .thenReturn(isLaunchable)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index c4ae2db..9203f05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -55,7 +55,11 @@
MockitoAnnotations.initMocks(this)
testScope = TestScope()
- underTest = DeviceEntryFingerprintAuthRepositoryImpl(keyguardUpdateMonitor)
+ underTest =
+ DeviceEntryFingerprintAuthRepositoryImpl(
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
index 1da7241..68fff26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt
@@ -23,6 +23,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.FakeBiometricRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.util.time.FakeSystemClock
@@ -46,6 +47,8 @@
private lateinit var underTest: AlternateBouncerInteractor
private lateinit var bouncerRepository: KeyguardBouncerRepository
private lateinit var biometricRepository: FakeBiometricRepository
+ private lateinit var deviceEntryFingerprintAuthRepository:
+ FakeDeviceEntryFingerprintAuthRepository
@Mock private lateinit var systemClock: SystemClock
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var bouncerLogger: TableLogBuffer
@@ -62,11 +65,13 @@
bouncerLogger,
)
biometricRepository = FakeBiometricRepository()
+ deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
featureFlags = FakeFeatureFlags().apply { this.set(Flags.MODERN_ALTERNATE_BOUNCER, true) }
underTest =
AlternateBouncerInteractor(
bouncerRepository,
biometricRepository,
+ deviceEntryFingerprintAuthRepository,
systemClock,
keyguardUpdateMonitor,
featureFlags,
@@ -112,6 +117,14 @@
}
@Test
+ fun canShowAlternateBouncerForFingerprint_fingerprintLockedOut() {
+ givenCanShowAlternateBouncer()
+ deviceEntryFingerprintAuthRepository.setLockedOut(true)
+
+ assertFalse(underTest.canShowAlternateBouncerForFingerprint())
+ }
+
+ @Test
fun show_whenCanShow() {
givenCanShowAlternateBouncer()
@@ -148,6 +161,7 @@
biometricRepository.setFingerprintEnrolled(true)
biometricRepository.setStrongBiometricAllowed(true)
biometricRepository.setFingerprintEnabledByDevicePolicy(true)
+ deviceEntryFingerprintAuthRepository.setLockedOut(false)
}
private fun givenCannotShowAlternateBouncer() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
new file mode 100644
index 0000000..9d60b16
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.content.Intent
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.SysuiTestCase
+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.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+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.anyBoolean
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardLongPressInteractorTest : SysuiTestCase() {
+
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var logger: UiEventLogger
+
+ private lateinit var underTest: KeyguardLongPressInteractor
+
+ private lateinit var testScope: TestScope
+ private lateinit var keyguardRepository: FakeKeyguardRepository
+ private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ runBlocking { createUnderTest() }
+ }
+
+ @Test
+ fun isEnabled() =
+ testScope.runTest {
+ val isEnabled = collectLastValue(underTest.isLongPressHandlingEnabled)
+ KeyguardState.values().forEach { keyguardState ->
+ setUpState(
+ keyguardState = keyguardState,
+ )
+
+ if (keyguardState == KeyguardState.LOCKSCREEN) {
+ assertThat(isEnabled()).isTrue()
+ } else {
+ assertThat(isEnabled()).isFalse()
+ }
+ }
+ }
+
+ @Test
+ fun `isEnabled - always false when quick settings are visible`() =
+ testScope.runTest {
+ val isEnabled = collectLastValue(underTest.isLongPressHandlingEnabled)
+ KeyguardState.values().forEach { keyguardState ->
+ setUpState(
+ keyguardState = keyguardState,
+ isQuickSettingsVisible = true,
+ )
+
+ assertThat(isEnabled()).isFalse()
+ }
+ }
+
+ @Test
+ fun `long-pressed - pop-up clicked - starts activity`() =
+ testScope.runTest {
+ val menu = collectLastValue(underTest.menu)
+ runCurrent()
+
+ val x = 100
+ val y = 123
+ underTest.onLongPress(x, y)
+ assertThat(menu()).isNotNull()
+ assertThat(menu()?.position?.x).isEqualTo(x)
+ assertThat(menu()?.position?.y).isEqualTo(y)
+
+ menu()?.onClicked?.invoke()
+
+ assertThat(menu()).isNull()
+ verify(activityStarter).dismissKeyguardThenExecute(any(), any(), anyBoolean())
+ }
+
+ @Test
+ fun `long-pressed - pop-up dismissed - never starts activity`() =
+ testScope.runTest {
+ val menu = collectLastValue(underTest.menu)
+ runCurrent()
+
+ menu()?.onDismissed?.invoke()
+
+ assertThat(menu()).isNull()
+ verify(activityStarter, never()).dismissKeyguardThenExecute(any(), any(), anyBoolean())
+ }
+
+ @Suppress("DEPRECATION") // We're okay using ACTION_CLOSE_SYSTEM_DIALOGS on system UI.
+ @Test
+ fun `long pressed - close dialogs broadcast received - popup dismissed`() =
+ testScope.runTest {
+ val menu = collectLastValue(underTest.menu)
+ runCurrent()
+
+ underTest.onLongPress(123, 456)
+ assertThat(menu()).isNotNull()
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { broadcastReceiver ->
+ broadcastReceiver.onReceive(context, Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ }
+
+ assertThat(menu()).isNull()
+ }
+
+ @Test
+ fun `logs when menu is shown`() =
+ testScope.runTest {
+ collectLastValue(underTest.menu)
+ runCurrent()
+
+ underTest.onLongPress(100, 123)
+
+ verify(logger)
+ .log(KeyguardLongPressInteractor.LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_SHOWN)
+ }
+
+ @Test
+ fun `logs when menu is clicked`() =
+ testScope.runTest {
+ val menu = collectLastValue(underTest.menu)
+ runCurrent()
+
+ underTest.onLongPress(100, 123)
+ menu()?.onClicked?.invoke()
+
+ verify(logger)
+ .log(KeyguardLongPressInteractor.LogEvents.LOCK_SCREEN_LONG_PRESS_POPUP_CLICKED)
+ }
+
+ private suspend fun createUnderTest(
+ isLongPressFeatureEnabled: Boolean = true,
+ isRevampedWppFeatureEnabled: Boolean = true,
+ ) {
+ testScope = TestScope()
+ keyguardRepository = FakeKeyguardRepository()
+ keyguardTransitionRepository = FakeKeyguardTransitionRepository()
+
+ underTest =
+ KeyguardLongPressInteractor(
+ unsafeContext = context,
+ scope = testScope.backgroundScope,
+ transitionInteractor =
+ KeyguardTransitionInteractor(
+ repository = keyguardTransitionRepository,
+ ),
+ repository = keyguardRepository,
+ activityStarter = activityStarter,
+ logger = logger,
+ featureFlags =
+ FakeFeatureFlags().apply {
+ set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, isLongPressFeatureEnabled)
+ set(Flags.REVAMPED_WALLPAPER_UI, isRevampedWppFeatureEnabled)
+ },
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ )
+ setUpState()
+ }
+
+ private suspend fun setUpState(
+ keyguardState: KeyguardState = KeyguardState.LOCKSCREEN,
+ isQuickSettingsVisible: Boolean = false,
+ ) {
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ to = keyguardState,
+ ),
+ )
+ keyguardRepository.setQuickSettingsVisible(isVisible = isQuickSettingsVisible)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 7c3c9d2..8fd15c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -29,6 +29,7 @@
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.widget.LinearLayout;
+import android.widget.SeekBar;
import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
@@ -43,6 +44,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import java.util.ArrayList;
import java.util.List;
@@ -57,6 +60,7 @@
private static final String TEST_DEVICE_ID_1 = "test_device_id_1";
private static final String TEST_DEVICE_ID_2 = "test_device_id_2";
private static final String TEST_SESSION_NAME = "test_session_name";
+
private static final int TEST_MAX_VOLUME = 20;
private static final int TEST_CURRENT_VOLUME = 10;
@@ -69,6 +73,8 @@
private IconCompat mIconCompat = mock(IconCompat.class);
private View mDialogLaunchView = mock(View.class);
+ @Captor
+ private ArgumentCaptor<SeekBar.OnSeekBarChangeListener> mOnSeekBarChangeListenerCaptor;
private MediaOutputAdapter mMediaOutputAdapter;
private MediaOutputAdapter.MediaDeviceViewHolder mViewHolder;
private List<MediaDevice> mMediaDevices = new ArrayList<>();
@@ -78,6 +84,7 @@
@Before
public void setUp() {
when(mMediaOutputController.isAdvancedLayoutSupported()).thenReturn(false);
+ when(mMediaOutputController.isSubStatusSupported()).thenReturn(false);
when(mMediaOutputController.getMediaItemList()).thenReturn(mMediaItems);
when(mMediaOutputController.getMediaDevices()).thenReturn(mMediaDevices);
when(mMediaOutputController.hasAdjustVolumeUserRestriction()).thenReturn(false);
@@ -348,6 +355,24 @@
}
@Test
+ public void onBindViewHolder_dragSeekbar_setsVolume() {
+ mOnSeekBarChangeListenerCaptor = ArgumentCaptor.forClass(
+ SeekBar.OnSeekBarChangeListener.class);
+ MediaOutputSeekbar mSpySeekbar = spy(mViewHolder.mSeekBar);
+ mViewHolder.mSeekBar = mSpySeekbar;
+ when(mMediaDevice1.getMaxVolume()).thenReturn(TEST_MAX_VOLUME);
+ when(mMediaDevice1.getCurrentVolume()).thenReturn(TEST_MAX_VOLUME);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ verify(mViewHolder.mSeekBar).setOnSeekBarChangeListener(
+ mOnSeekBarChangeListenerCaptor.capture());
+
+ mOnSeekBarChangeListenerCaptor.getValue().onStopTrackingTouch(mViewHolder.mSeekBar);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ verify(mMediaOutputController).logInteractionAdjustVolume(mMediaDevice1);
+ }
+
+ @Test
public void onBindViewHolder_bindSelectableDevice_verifyView() {
List<MediaDevice> selectableDevices = new ArrayList<>();
selectableDevices.add(mMediaDevice2);
@@ -404,6 +429,24 @@
}
@Test
+ public void subStatusSupported_onBindViewHolder_bindFailedStateDevice_verifyView() {
+ String deviceStatus = "";
+ when(mMediaOutputController.isSubStatusSupported()).thenReturn(true);
+ when(mMediaDevice2.hasDisabledReason()).thenReturn(true);
+ when(mMediaDevice2.getDisableReason()).thenReturn(-1);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 1);
+
+ assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mSubTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mSubTitleText.getText()).isEqualTo(deviceStatus);
+ assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_2);
+ }
+
+ @Test
public void onBindViewHolder_inTransferring_bindTransferringDevice_verifyView() {
when(mMediaOutputController.isAnyDeviceTransferring()).thenReturn(true);
when(mMediaDevice1.getState()).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 117751c..7c36e46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -93,6 +93,11 @@
private static final String TEST_SONG = "test_song";
private static final String TEST_SESSION_ID = "test_session_id";
private static final String TEST_SESSION_NAME = "test_session_name";
+ private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
+ private final ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController = mock(
+ ActivityLaunchAnimator.Controller.class);
+ private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
+ NearbyMediaDevicesManager.class);
// Mock
private MediaController mMediaController = mock(MediaController.class);
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
@@ -111,12 +116,7 @@
private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
- private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private FeatureFlags mFlags = mock(FeatureFlags.class);
- private final ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController = mock(
- ActivityLaunchAnimator.Controller.class);
- private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
- NearbyMediaDevicesManager.class);
private View mDialogLaunchView = mock(View.class);
private MediaOutputController.Callback mCallback = mock(MediaOutputController.Callback.class);
@@ -522,6 +522,17 @@
}
@Test
+ public void logInteractionAdjustVolume_triggersFromMetricLogger() {
+ MediaOutputMetricLogger spyMediaOutputMetricLogger = spy(
+ mMediaOutputController.mMetricLogger);
+ mMediaOutputController.mMetricLogger = spyMediaOutputMetricLogger;
+
+ mMediaOutputController.logInteractionAdjustVolume(mMediaDevice1);
+
+ verify(spyMediaOutputMetricLogger).logInteractionAdjustVolume(mMediaDevice1);
+ }
+
+ @Test
public void getSessionVolumeMax_triggersFromLocalMediaManager() {
mMediaOutputController.getSessionVolumeMax();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
index 87a1f12..c63ca3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderCoordinatorTest.kt
@@ -47,7 +47,6 @@
import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.ChipbarLogger
-import com.android.systemui.temporarydisplay.chipbar.FakeChipbarCoordinator
import com.android.systemui.temporarydisplay.chipbar.SwipeChipbarAwayGestureHandler
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -137,7 +136,7 @@
uiEventLogger = MediaTttSenderUiEventLogger(uiEventLoggerFake)
chipbarCoordinator =
- FakeChipbarCoordinator(
+ ChipbarCoordinator(
context,
chipbarLogger,
windowManager,
@@ -161,6 +160,7 @@
chipbarCoordinator,
commandQueue,
context,
+ dumpManager,
logger,
mediaTttFlags,
uiEventLogger,
@@ -179,6 +179,7 @@
chipbarCoordinator,
commandQueue,
context,
+ dumpManager,
logger,
mediaTttFlags,
uiEventLogger,
@@ -540,6 +541,7 @@
val viewCaptor = ArgumentCaptor.forClass(View::class.java)
verify(windowManager).addView(viewCaptor.capture(), any())
verify(windowManager).removeView(viewCaptor.value)
+ verify(logger).logStateMapRemoval(eq(DEFAULT_ID), any())
}
@Test
@@ -739,6 +741,99 @@
verify(windowManager, never()).addView(any(), any())
}
+ /** Regression test for b/266217596. */
+ @Test
+ fun toReceiver_triggeredThenFar_thenSucceeded_updatesToSucceeded() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+ routeInfo,
+ null,
+ )
+
+ // WHEN a FAR command comes in
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+ routeInfo,
+ null,
+ )
+
+ // THEN it is ignored and the chipbar is stilled displayed
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText())
+ assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE)
+ verify(windowManager, never()).removeView(any())
+
+ // WHEN a SUCCEEDED command comes in
+ val succeededRouteInfo =
+ MediaRoute2Info.Builder(DEFAULT_ID, "Tablet Succeeded")
+ .addFeature("feature")
+ .setClientPackageName(PACKAGE_NAME)
+ .build()
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+ succeededRouteInfo,
+ /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ },
+ )
+
+ // THEN it is *not* marked as an invalid transition and the chipbar updates to the succeeded
+ // state. (The "invalid transition" would be FAR => SUCCEEDED.)
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(
+ ChipStateSender.TRANSFER_TO_RECEIVER_SUCCEEDED.getExpectedStateText(
+ "Tablet Succeeded"
+ )
+ )
+ assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE)
+ assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
+ }
+
+ /** Regression test for b/266217596. */
+ @Test
+ fun toThisDevice_triggeredThenFar_thenSucceeded_updatesToSucceeded() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+ routeInfo,
+ null,
+ )
+
+ // WHEN a FAR command comes in
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+ routeInfo,
+ null,
+ )
+
+ // THEN it is ignored and the chipbar is stilled displayed
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.getExpectedStateText())
+ assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE)
+ verify(windowManager, never()).removeView(any())
+
+ // WHEN a SUCCEEDED command comes in
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+ routeInfo,
+ /* undoCallback= */ object : IUndoMediaTransferCallback.Stub() {
+ override fun onUndoTriggered() {}
+ },
+ )
+
+ // THEN it is *not* marked as an invalid transition and the chipbar updates to the succeeded
+ // state. (The "invalid transition" would be FAR => SUCCEEDED.)
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(
+ ChipStateSender.TRANSFER_TO_THIS_DEVICE_SUCCEEDED.getExpectedStateText(
+ "Tablet Succeeded"
+ )
+ )
+ assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.GONE)
+ assertThat(chipbarView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
+ }
+
@Test
fun receivesNewStateFromCommandQueue_isLogged() {
commandQueueCallback.updateMediaTapToTransferSenderDisplay(
@@ -932,6 +1027,7 @@
mockChipbarCoordinator,
commandQueue,
context,
+ dumpManager,
logger,
mediaTttFlags,
uiEventLogger,
@@ -958,6 +1054,7 @@
mockChipbarCoordinator,
commandQueue,
context,
+ dumpManager,
logger,
mediaTttFlags,
uiEventLogger,
@@ -975,9 +1072,10 @@
verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor))
// WHEN the listener is notified that the view has been removed
- listenerCaptor.value.onInfoPermanentlyRemoved(DEFAULT_ID)
+ listenerCaptor.value.onInfoPermanentlyRemoved(DEFAULT_ID, "reason")
// THEN the media coordinator unregisters the listener
+ verify(logger).logStateMapRemoval(DEFAULT_ID, "reason")
verify(mockChipbarCoordinator).unregisterListener(listenerCaptor.value)
}
@@ -989,6 +1087,7 @@
mockChipbarCoordinator,
commandQueue,
context,
+ dumpManager,
logger,
mediaTttFlags,
uiEventLogger,
@@ -1006,7 +1105,7 @@
verify(mockChipbarCoordinator).registerListener(capture(listenerCaptor))
// WHEN the listener is notified that a different view has been removed
- listenerCaptor.value.onInfoPermanentlyRemoved("differentViewId")
+ listenerCaptor.value.onInfoPermanentlyRemoved("differentViewId", "reason")
// THEN the media coordinator doesn't unregister the listener
verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value)
@@ -1020,6 +1119,7 @@
mockChipbarCoordinator,
commandQueue,
context,
+ dumpManager,
logger,
mediaTttFlags,
uiEventLogger,
@@ -1055,6 +1155,7 @@
mockChipbarCoordinator,
commandQueue,
context,
+ dumpManager,
logger,
mediaTttFlags,
uiEventLogger,
@@ -1084,10 +1185,173 @@
verify(mockChipbarCoordinator, atLeast(1)).registerListener(capture(listenerCaptor))
// THEN one of them is removed
- listenerCaptor.value.onInfoPermanentlyRemoved("route1")
+ listenerCaptor.value.onInfoPermanentlyRemoved("route1", "reason")
// THEN the media coordinator doesn't unregister the listener (since route2 is still active)
verify(mockChipbarCoordinator, never()).unregisterListener(listenerCaptor.value)
+ verify(logger).logStateMapRemoval("route1", "reason")
+ }
+
+ /** Regression test for b/266218672. */
+ @Test
+ fun twoIdsDisplayed_oldIdIsFar_viewStillDisplayed() {
+ // WHEN there are two different media transfers with different IDs
+ val route1 =
+ MediaRoute2Info.Builder("route1", OTHER_DEVICE_NAME)
+ .addFeature("feature")
+ .setClientPackageName(PACKAGE_NAME)
+ .build()
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ route1,
+ null,
+ )
+ verify(windowManager).addView(any(), any())
+ reset(windowManager)
+
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ MediaRoute2Info.Builder("route2", "Route 2 name")
+ .addFeature("feature")
+ .setClientPackageName(PACKAGE_NAME)
+ .build(),
+ null,
+ )
+ val newView = getChipbarView()
+
+ // WHEN there's a FAR event for the earlier one
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+ route1,
+ null,
+ )
+
+ // THEN it's ignored and the more recent one is still displayed
+ assertThat(newView.getChipText())
+ .isEqualTo(
+ ChipStateSender.ALMOST_CLOSE_TO_START_CAST.getExpectedStateText("Route 2 name")
+ )
+ }
+
+ /** Regression test for b/266218672. */
+ @Test
+ fun receiverSucceededThenTimedOut_internalStateResetAndCanDisplayAlmostCloseToEnd() {
+ displayReceiverTriggered()
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+ routeInfo,
+ null,
+ )
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+ verify(windowManager).removeView(any())
+
+ reset(windowManager)
+
+ // WHEN we try to show ALMOST_CLOSE_TO_END
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ routeInfo,
+ null,
+ )
+
+ // THEN it succeeds
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(ChipStateSender.ALMOST_CLOSE_TO_END_CAST.getExpectedStateText())
+ }
+
+ /** Regression test for b/266218672. */
+ @Test
+ fun receiverSucceededThenTimedOut_internalStateResetAndCanDisplayReceiverTriggered() {
+ displayReceiverTriggered()
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+ routeInfo,
+ null,
+ )
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+ verify(windowManager).removeView(any())
+
+ reset(windowManager)
+
+ // WHEN we try to show RECEIVER_TRIGGERED
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+ routeInfo,
+ null,
+ )
+
+ // THEN it succeeds
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(ChipStateSender.TRANSFER_TO_RECEIVER_TRIGGERED.getExpectedStateText())
+ assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE)
+ }
+
+ /** Regression test for b/266218672. */
+ @Test
+ fun toThisDeviceSucceededThenTimedOut_internalStateResetAndCanDisplayAlmostCloseToStart() {
+ displayThisDeviceTriggered()
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+ routeInfo,
+ null,
+ )
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+ verify(windowManager).removeView(any())
+
+ reset(windowManager)
+
+ // WHEN we try to show ALMOST_CLOSE_TO_START
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ routeInfo,
+ null,
+ )
+
+ // THEN it succeeds
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.getExpectedStateText())
+ }
+
+ /** Regression test for b/266218672. */
+ @Test
+ fun toThisDeviceSucceededThenTimedOut_internalStateResetAndCanDisplayThisDeviceTriggered() {
+ displayThisDeviceTriggered()
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+ routeInfo,
+ null,
+ )
+
+ fakeClock.advanceTime(TIMEOUT + 1L)
+ verify(windowManager).removeView(any())
+
+ reset(windowManager)
+
+ // WHEN we try to show THIS_DEVICE_TRIGGERED
+ val newRouteInfo =
+ MediaRoute2Info.Builder(DEFAULT_ID, "New Name")
+ .addFeature("feature")
+ .setClientPackageName(PACKAGE_NAME)
+ .build()
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+ newRouteInfo,
+ null,
+ )
+
+ // THEN it succeeds
+ val chipbarView = getChipbarView()
+ assertThat(chipbarView.getChipText())
+ .isEqualTo(
+ ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.getExpectedStateText("New Name")
+ )
+ assertThat(chipbarView.getLoadingIcon().visibility).isEqualTo(View.VISIBLE)
}
private fun getChipbarView(): ViewGroup {
@@ -1107,8 +1371,10 @@
private fun ViewGroup.getUndoButton(): View = this.requireViewById(R.id.end_button)
- private fun ChipStateSender.getExpectedStateText(): String? {
- return this.getChipTextString(context, OTHER_DEVICE_NAME).loadText(context)
+ private fun ChipStateSender.getExpectedStateText(
+ otherDeviceName: String = OTHER_DEVICE_NAME,
+ ): String? {
+ return this.getChipTextString(context, otherDeviceName).loadText(context)
}
// display receiver triggered state helper method to make sure we start from a valid state
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
index 59cc43f..0033757 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLoggerTest.kt
@@ -87,6 +87,32 @@
assertThat(actualString).contains(bypassReason)
}
+ @Test
+ fun logStateMap_bufferHasInfo() {
+ val map =
+ mapOf(
+ "123" to ChipStateSender.ALMOST_CLOSE_TO_START_CAST,
+ "456" to ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+ )
+
+ logger.logStateMap(map)
+
+ val actualString = getStringFromBuffer()
+ assertThat(actualString).contains("123")
+ assertThat(actualString).contains(ChipStateSender.ALMOST_CLOSE_TO_START_CAST.name)
+ assertThat(actualString).contains("456")
+ assertThat(actualString).contains(ChipStateSender.TRANSFER_TO_THIS_DEVICE_TRIGGERED.name)
+ }
+
+ @Test
+ fun logStateMapRemoval_bufferHasInfo() {
+ logger.logStateMapRemoval("456", "testReason")
+
+ val actualString = getStringFromBuffer()
+ assertThat(actualString).contains("456")
+ assertThat(actualString).contains("testReason")
+ }
+
private fun getStringFromBuffer(): String {
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
index 9bcfd5b..1a93adc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
@@ -26,6 +26,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.FakeDisplayTracker;
import org.junit.Before;
import org.junit.Test;
@@ -46,7 +47,8 @@
@Before
public void setup() {
- mFlagsContainer = new SysUiState();
+ FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
+ mFlagsContainer = new SysUiState(displayTracker);
mCallback = mock(SysUiState.SysUiStateCallback.class);
mFlagsContainer.addCallback(mCallback);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
index 92652a7..3eb7329 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
@@ -40,6 +40,7 @@
import com.android.systemui.assist.AssistManager;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.After;
@@ -65,6 +66,7 @@
private ImageReader mReader;
private NavigationBarView mNavBar;
private VirtualDisplay mVirtualDisplay;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@Before
public void setup() {
@@ -83,6 +85,7 @@
mDependency.injectTestDependency(EdgeBackGestureHandler.Factory.class,
mEdgeBackGestureHandlerFactory);
mNavBar = new NavigationBarView(context, null);
+ mNavBar.setDisplayTracker(mDisplayTracker);
}
private Display createVirtualDisplay() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index 8058b85..aacbf8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -37,6 +37,7 @@
import static org.mockito.Mockito.when;
import android.content.res.Configuration;
+import android.hardware.display.DisplayManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.util.SparseArray;
@@ -50,6 +51,7 @@
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.model.SysUiState;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.CommandQueue;
@@ -81,6 +83,7 @@
private NavigationBar mDefaultNavBar;
private NavigationBar mSecondaryNavBar;
private StaticMockitoSession mMockitoSession;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@Mock
private CommandQueue mCommandQueue;
@@ -92,6 +95,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
mNavigationBarController = spy(
new NavigationBarController(mContext,
mock(OverviewProxyService.class),
@@ -110,7 +114,8 @@
Optional.of(mock(Pip.class)),
Optional.of(mock(BackAnimation.class)),
mock(FeatureFlags.class),
- mock(SecureSettings.class)));
+ mock(SecureSettings.class),
+ mDisplayTracker));
initializeNavigationBars();
mMockitoSession = mockitoSession().mockStatic(Utilities.class).startMocking();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 2ad865e..764ddc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -87,6 +87,7 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowView;
@@ -495,7 +496,8 @@
Optional.of(mock(BackAnimation.class)),
mUserContextProvider,
mWakefulnessLifecycle,
- mTaskStackChangeListeners));
+ mTaskStackChangeListeners,
+ new FakeDisplayTracker(mContext)));
}
private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
index cafd2cf..5270737 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
@@ -36,6 +36,7 @@
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.phone.BarTransitions;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -63,6 +64,7 @@
IWindowManager mIWindowManager;
private NavigationBarTransitions mTransitions;
+ private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@Before
public void setup() {
@@ -86,7 +88,7 @@
when(navBar.getCurrentView()).thenReturn(navBar);
when(navBar.findViewById(anyInt())).thenReturn(navBar);
mTransitions = new NavigationBarTransitions(
- navBar, mIWindowManager, mLightBarTransitionsFactory);
+ navBar, mIWindowManager, mLightBarTransitionsFactory, mDisplayTracker);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
index bbe60f4..18be92b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskIntentResolverTest.kt
@@ -16,17 +16,14 @@
package com.android.systemui.notetask
-import android.content.ComponentName
+import android.app.role.RoleManager
import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
-import android.content.pm.PackageManager.ResolveInfoFlags
-import android.content.pm.ResolveInfo
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
+import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -47,172 +44,39 @@
internal class NoteTaskIntentResolverTest : SysuiTestCase() {
@Mock lateinit var packageManager: PackageManager
+ @Mock lateinit var roleManager: RoleManager
- private lateinit var resolver: NoteTaskIntentResolver
+ private lateinit var underTest: NoteTaskIntentResolver
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- resolver = NoteTaskIntentResolver(packageManager)
- }
-
- private fun createResolveInfo(
- activityInfo: ActivityInfo? = createActivityInfo(),
- ): ResolveInfo {
- return ResolveInfo().apply { this.activityInfo = activityInfo }
- }
-
- private fun createActivityInfo(
- packageName: String = "PackageName",
- name: String? = "ActivityName",
- exported: Boolean = true,
- enabled: Boolean = true,
- showWhenLocked: Boolean = true,
- turnScreenOn: Boolean = true,
- ): ActivityInfo {
- return ActivityInfo().apply {
- this.name = name
- this.exported = exported
- this.enabled = enabled
- if (showWhenLocked) {
- flags = flags or ActivityInfo.FLAG_SHOW_WHEN_LOCKED
- }
- if (turnScreenOn) {
- flags = flags or ActivityInfo.FLAG_TURN_SCREEN_ON
- }
- this.applicationInfo = ApplicationInfo().apply { this.packageName = packageName }
- }
- }
-
- private fun givenQueryIntentActivities(block: () -> List<ResolveInfo>) {
- whenever(packageManager.queryIntentActivities(any(), any<ResolveInfoFlags>()))
- .thenReturn(block())
- }
-
- private fun givenResolveActivity(block: () -> ResolveInfo?) {
- whenever(packageManager.resolveActivity(any(), any<ResolveInfoFlags>())).thenReturn(block())
+ underTest = NoteTaskIntentResolver(context, roleManager)
}
@Test
- fun resolveIntent_shouldReturnNotesIntent() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo()) }
+ fun resolveIntent_shouldReturnIntentInStylusMode() {
+ val packageName = "com.android.note.app"
+ whenever(roleManager.getRoleHoldersAsUser(NoteTaskIntentResolver.ROLE_NOTES, context.user))
+ .then { listOf(packageName) }
- val actual = resolver.resolveIntent()
+ val actual = underTest.resolveIntent()
- val expected =
- Intent(ACTION_CREATE_NOTE)
- .setPackage("PackageName")
- .setComponent(ComponentName("PackageName", "ActivityName"))
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- // Compares the string representation of both intents, as they are different instances.
- assertThat(actual.toString()).isEqualTo(expected.toString())
+ requireNotNull(actual) { "Intent must not be null" }
+ assertThat(actual.action).isEqualTo(ACTION_CREATE_NOTE)
+ assertThat(actual.`package`).isEqualTo(packageName)
+ val expectedExtra = actual.getExtra(NoteTaskIntentResolver.INTENT_EXTRA_USE_STYLUS_MODE)
+ assertThat(expectedExtra).isEqualTo(true)
+ val expectedFlag = actual.flags and Intent.FLAG_ACTIVITY_NEW_TASK
+ assertThat(expectedFlag).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK)
}
@Test
- fun resolveIntent_activityInfoEnabledIsFalse_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity {
- createResolveInfo(activityInfo = createActivityInfo(enabled = false))
- }
+ fun resolveIntent_noRoleHolderIsSet_shouldReturnNull() {
+ whenever(roleManager.getRoleHoldersAsUser(eq(NoteTaskIntentResolver.ROLE_NOTES), any()))
+ .then { listOf<String>() }
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_activityInfoExportedIsFalse_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity {
- createResolveInfo(activityInfo = createActivityInfo(exported = false))
- }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_activityInfoShowWhenLockedIsFalse_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity {
- createResolveInfo(activityInfo = createActivityInfo(showWhenLocked = false))
- }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_activityInfoTurnScreenOnIsFalse_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity {
- createResolveInfo(activityInfo = createActivityInfo(turnScreenOn = false))
- }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_activityInfoNameIsBlank_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo(name = "")) }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_activityInfoNameIsNull_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity { createResolveInfo(activityInfo = createActivityInfo(name = null)) }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_activityInfoIsNull_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity { createResolveInfo(activityInfo = null) }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_resolveActivityIsNull_shouldReturnNull() {
- givenQueryIntentActivities { listOf(createResolveInfo()) }
- givenResolveActivity { null }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_packageNameIsBlank_shouldReturnNull() {
- givenQueryIntentActivities {
- listOf(createResolveInfo(createActivityInfo(packageName = "")))
- }
-
- val actual = resolver.resolveIntent()
-
- assertThat(actual).isNull()
- }
-
- @Test
- fun resolveIntent_activityNotFoundForAction_shouldReturnNull() {
- givenQueryIntentActivities { emptyList() }
-
- val actual = resolver.resolveIntent()
+ val actual = underTest.resolveIntent()
assertThat(actual).isNull()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 42ef9c2..4caa50f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -60,6 +60,7 @@
import com.android.systemui.qs.external.TileServiceRequestController;
import com.android.systemui.qs.footer.ui.binder.FooterActionsViewBinder;
import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -494,7 +495,7 @@
@Override
protected Fragment instantiate(Context context, String className, Bundle arguments) {
MockitoAnnotations.initMocks(this);
- CommandQueue commandQueue = new CommandQueue(context);
+ CommandQueue commandQueue = new CommandQueue(context, new FakeDisplayTracker(context));
setupQsComponent();
setUpViews();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 2bd068a..8644b5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -35,12 +35,14 @@
import com.android.internal.logging.MetricsLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.animation.LaunchableFrameLayout
import com.android.systemui.classifier.FalsingManagerFake
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
@@ -90,6 +92,7 @@
private lateinit var customTile: CustomTile
private lateinit var testableLooper: TestableLooper
private lateinit var customTileBuilder: CustomTile.Builder
+ private val displayTracker = FakeDisplayTracker(mContext)
@Before
fun setUp() {
@@ -119,7 +122,8 @@
activityStarter,
qsLogger,
customTileStatePersister,
- tileServices
+ tileServices,
+ displayTracker
)
customTile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
@@ -339,7 +343,7 @@
val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
tile.qsTile.activityLaunchForClick = pi
- tile.handleClick(mock(View::class.java))
+ tile.handleClick(mock(LaunchableFrameLayout::class.java))
testableLooper.processAllMessages()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
index e1eda11..d5014fa36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionProxyReceiverTest.java
@@ -39,6 +39,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -67,6 +68,7 @@
private PendingIntent mMockPendingIntent;
private Intent mIntent;
+ private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@Before
public void setup() throws InterruptedException, ExecutionException, TimeoutException {
@@ -135,10 +137,11 @@
if (withStatusBar) {
return new ActionProxyReceiver(
Optional.of(mMockCentralSurfaces), mMockActivityManagerWrapper,
- mMockScreenshotSmartActions);
+ mMockScreenshotSmartActions, mDisplayTracker);
} else {
return new ActionProxyReceiver(
- Optional.empty(), mMockActivityManagerWrapper, mMockScreenshotSmartActions);
+ Optional.empty(), mMockActivityManagerWrapper, mMockScreenshotSmartActions,
+ mDisplayTracker);
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
index 17396b1..e70fa2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
@@ -31,6 +31,7 @@
import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase
import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
+import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
@@ -126,8 +127,10 @@
val userManager = mock<UserManager>()
val atmService = mock<IActivityTaskManager>()
val dispatcher = Dispatchers.Unconfined
+ val displayTracker = FakeDisplayTracker(mContext)
- return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher) {
+ return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher,
+ displayTracker) {
override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER)
override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks
override suspend fun isNotificationShadeExpanded() = shadeExpanded
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
index bd04b3c..e8905ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/WorkProfileMessageControllerTest.java
@@ -65,7 +65,7 @@
@Mock
private Context mContext;
@Mock
- private WorkProfileMessageController.WorkProfileMessageDisplay mMessageDisplay;
+ private MessageContainerController mMessageDisplay;
@Mock
private Drawable mActivityIcon;
@Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt
new file mode 100644
index 0000000..ae976a0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.settings
+
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+import android.hardware.display.DisplayManagerGlobal
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import android.view.Display
+import android.view.DisplayAdjustments
+import android.view.DisplayInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class DisplayTrackerImplTest : SysuiTestCase() {
+ @Mock private lateinit var displayManager: DisplayManager
+ @Mock private lateinit var handler: Handler
+
+ private val executor = Executor(Runnable::run)
+ private lateinit var mDefaultDisplay: Display
+ private lateinit var mSecondaryDisplay: Display
+ private lateinit var tracker: DisplayTrackerImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ mDefaultDisplay =
+ Display(
+ DisplayManagerGlobal.getInstance(),
+ Display.DEFAULT_DISPLAY,
+ DisplayInfo(),
+ DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
+ )
+ mSecondaryDisplay =
+ Display(
+ DisplayManagerGlobal.getInstance(),
+ Display.DEFAULT_DISPLAY + 1,
+ DisplayInfo(),
+ DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
+ )
+
+ `when`(displayManager.displays).thenReturn(arrayOf(mDefaultDisplay, mSecondaryDisplay))
+
+ tracker = DisplayTrackerImpl(displayManager, handler)
+ }
+
+ @Test
+ fun testGetDefaultDisplay() {
+ assertThat(tracker.defaultDisplayId).isEqualTo(Display.DEFAULT_DISPLAY)
+ }
+
+ @Test
+ fun testGetAllDisplays() {
+ assertThat(tracker.allDisplays).isEqualTo(arrayOf(mDefaultDisplay, mSecondaryDisplay))
+ }
+
+ @Test
+ fun registerCallback_registersDisplayListener() {
+ tracker.addDisplayChangeCallback(TestCallback(), executor)
+ verify(displayManager).registerDisplayListener(any(), any())
+ }
+
+ @Test
+ fun registerBrightnessCallback_registersDisplayListener() {
+ tracker.addBrightnessChangeCallback(TestCallback(), executor)
+ verify(displayManager)
+ .registerDisplayListener(any(), any(), eq(EVENT_FLAG_DISPLAY_BRIGHTNESS))
+ }
+
+ @Test
+ fun unregisterCallback_displayListenerStillRegistered() {
+ val callback1 = TestCallback()
+ tracker.addDisplayChangeCallback(callback1, executor)
+ tracker.addDisplayChangeCallback(TestCallback(), executor)
+ tracker.removeCallback(callback1)
+
+ verify(displayManager, never()).unregisterDisplayListener(any())
+ }
+
+ @Test
+ fun unregisterLastCallback_unregistersDisplayListener() {
+ val callback = TestCallback()
+ tracker.addDisplayChangeCallback(callback, executor)
+ tracker.removeCallback(callback)
+
+ verify(displayManager).unregisterDisplayListener(any())
+ }
+
+ @Test
+ fun callbackCalledOnDisplayAdd() {
+ val testDisplay = 2
+ val callback = TestCallback()
+ tracker.addDisplayChangeCallback(callback, executor)
+ tracker.displayChangedListener.onDisplayAdded(testDisplay)
+
+ assertThat(callback.lastDisplayAdded).isEqualTo(testDisplay)
+ }
+
+ @Test
+ fun callbackCalledOnDisplayRemoved() {
+ val testDisplay = 2
+ val callback = TestCallback()
+ tracker.addDisplayChangeCallback(callback, executor)
+ tracker.displayChangedListener.onDisplayRemoved(testDisplay)
+
+ assertThat(callback.lastDisplayRemoved).isEqualTo(testDisplay)
+ }
+
+ @Test
+ fun callbackCalledOnDisplayChanged() {
+ val testDisplay = 2
+ val callback = TestCallback()
+ tracker.addDisplayChangeCallback(callback, executor)
+ tracker.displayChangedListener.onDisplayChanged(testDisplay)
+
+ assertThat(callback.lastDisplayChanged).isEqualTo(testDisplay)
+ }
+
+ @Test
+ fun callbackCalledOnBrightnessChanged() {
+ val testDisplay = 2
+ val callback = TestCallback()
+ tracker.addBrightnessChangeCallback(callback, executor)
+ tracker.displayBrightnessChangedListener.onDisplayChanged(testDisplay)
+
+ assertThat(callback.lastDisplayChanged).isEqualTo(testDisplay)
+ }
+
+ private class TestCallback : DisplayTracker.Callback {
+ var lastDisplayAdded = -1
+ var lastDisplayRemoved = -1
+ var lastDisplayChanged = -1
+
+ override fun onDisplayAdded(displayId: Int) {
+ lastDisplayAdded = displayId
+ }
+
+ override fun onDisplayRemoved(displayId: Int) {
+ lastDisplayRemoved = displayId
+ }
+
+ override fun onDisplayChanged(displayId: Int) {
+ lastDisplayChanged = displayId
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
index 3710281..57b6b2b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplReceiveTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.settings
+import android.app.IActivityManager
import android.content.Context
import android.content.Intent
import android.content.pm.UserInfo
@@ -51,6 +52,7 @@
@Mock private lateinit var context: Context
@Mock private lateinit var userManager: UserManager
+ @Mock private lateinit var iActivityManager: IActivityManager
@Mock(stubOnly = true) private lateinit var dumpManager: DumpManager
@Mock(stubOnly = true) private lateinit var handler: Handler
@@ -67,7 +69,7 @@
`when`(context.user).thenReturn(UserHandle.SYSTEM)
`when`(context.createContextAsUser(ArgumentMatchers.any(), anyInt())).thenReturn(context)
- tracker = UserTrackerImpl(context, userManager, dumpManager, handler)
+ tracker = UserTrackerImpl(context, userManager, iActivityManager, dumpManager, handler)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index e65bbb1..71ba215 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -16,11 +16,14 @@
package com.android.systemui.settings
+import android.app.IActivityManager
+import android.app.IUserSwitchObserver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.UserInfo
import android.os.Handler
+import android.os.IRemoteCallback
import android.os.UserHandle
import android.os.UserManager
import android.testing.AndroidTestingRunner
@@ -29,19 +32,20 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.util.mockito.capture
import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Executor
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.ArgumentMatchers.isNull
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-import java.util.concurrent.Executor
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -51,6 +55,10 @@
private lateinit var context: Context
@Mock
private lateinit var userManager: UserManager
+ @Mock
+ private lateinit var iActivityManager: IActivityManager
+ @Mock
+ private lateinit var userSwitchingReply: IRemoteCallback
@Mock(stubOnly = true)
private lateinit var dumpManager: DumpManager
@Mock(stubOnly = true)
@@ -76,7 +84,7 @@
listOf(info)
}
- tracker = UserTrackerImpl(context, userManager, dumpManager, handler)
+ tracker = UserTrackerImpl(context, userManager, iActivityManager, dumpManager, handler)
}
@Test
@@ -125,8 +133,7 @@
verify(context).registerReceiverForAllUsers(
eq(tracker), capture(captor), isNull(), eq(handler))
with(captor.value) {
- assertThat(countActions()).isEqualTo(7)
- assertThat(hasAction(Intent.ACTION_USER_SWITCHED)).isTrue()
+ assertThat(countActions()).isEqualTo(6)
assertThat(hasAction(Intent.ACTION_USER_INFO_CHANGED)).isTrue()
assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)).isTrue()
assertThat(hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)).isTrue()
@@ -158,8 +165,10 @@
tracker.initialize(0)
val newID = 5
- val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
- tracker.onReceive(context, intent)
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ verify(userSwitchingReply).sendResult(any())
verify(userManager).getProfiles(newID)
@@ -272,6 +281,24 @@
}
@Test
+ fun testCallbackCalledOnUserChanging() {
+ tracker.initialize(0)
+ val callback = TestCallback()
+ tracker.addCallback(callback, executor)
+
+ val newID = 5
+
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ verify(userSwitchingReply).sendResult(any())
+
+ assertThat(callback.calledOnUserChanging).isEqualTo(1)
+ assertThat(callback.lastUser).isEqualTo(newID)
+ assertThat(callback.lastUserContext?.userId).isEqualTo(newID)
+ }
+
+ @Test
fun testCallbackCalledOnUserChanged() {
tracker.initialize(0)
val callback = TestCallback()
@@ -279,8 +306,9 @@
val newID = 5
- val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, newID)
- tracker.onReceive(context, intent)
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onUserSwitchComplete(newID)
assertThat(callback.calledOnUserChanged).isEqualTo(1)
assertThat(callback.lastUser).isEqualTo(newID)
@@ -330,25 +358,36 @@
tracker.addCallback(callback, executor)
tracker.removeCallback(callback)
- val intent = Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE, 5)
- tracker.onReceive(context, intent)
+ val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
+ verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
+ captor.value.onUserSwitching(newID, userSwitchingReply)
+ verify(userSwitchingReply).sendResult(any())
+ captor.value.onUserSwitchComplete(newID)
val intentProfiles = Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
.putExtra(Intent.EXTRA_USER, UserHandle.of(profileID))
tracker.onReceive(context, intentProfiles)
+ assertThat(callback.calledOnUserChanging).isEqualTo(0)
assertThat(callback.calledOnUserChanged).isEqualTo(0)
assertThat(callback.calledOnProfilesChanged).isEqualTo(0)
}
private class TestCallback : UserTracker.Callback {
+ var calledOnUserChanging = 0
var calledOnUserChanged = 0
var calledOnProfilesChanged = 0
var lastUser: Int? = null
var lastUserContext: Context? = null
var lastUserProfiles = emptyList<UserInfo>()
+ override fun onUserChanging(newUser: Int, userContext: Context) {
+ calledOnUserChanging++
+ lastUser = newUser
+ lastUserContext = userContext
+ }
+
override fun onUserChanged(newUser: Int, userContext: Context) {
calledOnUserChanged++
lastUser = newUser
@@ -360,4 +399,4 @@
lastUserProfiles = profiles
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
index 9d1802a..58ade49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
@@ -28,6 +28,7 @@
import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
@@ -51,6 +52,7 @@
@Mock private lateinit var mainExecutor: Executor
@Mock private lateinit var backgroundHandler: Handler
@Mock private lateinit var brightnessSliderController: BrightnessSliderController
+ private val displayTracker = FakeDisplayTracker(mContext)
@Rule
@JvmField
@@ -60,6 +62,7 @@
override fun create(intent: Intent?): TestDialog {
return TestDialog(
userTracker,
+ displayTracker,
brightnessSliderControllerFactory,
mainExecutor,
backgroundHandler
@@ -105,12 +108,14 @@
class TestDialog(
userTracker: UserTracker,
+ displayTracker: FakeDisplayTracker,
brightnessSliderControllerFactory: BrightnessSliderController.Factory,
mainExecutor: Executor,
backgroundHandler: Handler
) :
BrightnessDialog(
userTracker,
+ displayTracker,
brightnessSliderControllerFactory,
mainExecutor,
backgroundHandler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
index b568122..2bf2a81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.shade
+import android.animation.Animator
import android.animation.ValueAnimator
import android.app.StatusBarManager
import android.content.Context
@@ -45,8 +46,8 @@
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -293,6 +294,34 @@
}
@Test
+ fun animatorListenersClearedAtEnd() {
+ val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+ whenever(view.animate()).thenReturn(animator)
+
+ mLargeScreenShadeHeaderController.startCustomizingAnimation(show = true, 0L)
+ val listenerCaptor = argumentCaptor<Animator.AnimatorListener>()
+ verify(animator).setListener(capture(listenerCaptor))
+
+ listenerCaptor.value.onAnimationEnd(mock())
+ verify(animator).setListener(null)
+ verify(animator).setUpdateListener(null)
+ }
+
+ @Test
+ fun animatorListenersClearedOnCancel() {
+ val animator = mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
+ whenever(view.animate()).thenReturn(animator)
+
+ mLargeScreenShadeHeaderController.startCustomizingAnimation(show = true, 0L)
+ val listenerCaptor = argumentCaptor<Animator.AnimatorListener>()
+ verify(animator).setListener(capture(listenerCaptor))
+
+ listenerCaptor.value.onAnimationCancel(mock())
+ verify(animator).setListener(null)
+ verify(animator).setUpdateListener(null)
+ }
+
+ @Test
fun demoMode_attachDemoMode() {
val cb = argumentCaptor<DemoMode>()
verify(demoModeController).addCallback(capture(cb))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 0f3d4a8..28f7edf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -97,6 +97,7 @@
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.common.ui.view.LongPressHandlingView;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
@@ -105,10 +106,12 @@
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel;
@@ -197,7 +200,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class NotificationPanelViewControllerTest extends SysuiTestCase {
private static final int SPLIT_SHADE_FULL_TRANSITION_DISTANCE = 400;
@@ -302,6 +305,8 @@
@Mock private GoneToDreamingTransitionViewModel mGoneToDreamingTransitionViewModel;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ @Mock private KeyguardInteractor mKeyguardInteractor;
+ @Mock private KeyguardLongPressViewModel mKeyuardLongPressViewModel;
@Mock private CoroutineDispatcher mMainDispatcher;
@Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
@Mock private MotionEvent mDownMotionEvent;
@@ -459,6 +464,9 @@
mMainHandler = new Handler(Looper.getMainLooper());
+ when(mView.requireViewById(R.id.keyguard_long_press))
+ .thenReturn(mock(LongPressHandlingView.class));
+
mNotificationPanelViewController = new NotificationPanelViewController(
mView,
mMainHandler,
@@ -528,7 +536,9 @@
mLockscreenToOccludedTransitionViewModel,
mMainDispatcher,
mKeyguardTransitionInteractor,
- mDumpManager);
+ mDumpManager,
+ mKeyuardLongPressViewModel,
+ mKeyguardInteractor);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
index bdafc7d..c915502a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
@@ -13,8 +13,11 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.fragments.FragmentHostManager
+import com.android.systemui.fragments.FragmentService
import com.android.systemui.navigationbar.NavigationModeController
import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
+import com.android.systemui.plugins.qs.QS
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
import com.android.systemui.util.concurrency.FakeExecutor
@@ -29,6 +32,7 @@
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.RETURNS_DEEP_STUBS
+import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.doNothing
import org.mockito.Mockito.eq
@@ -69,6 +73,10 @@
private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
@Mock
private lateinit var featureFlags: FeatureFlags
+ @Mock
+ private lateinit var fragmentService: FragmentService
+ @Mock
+ private lateinit var fragmentHostManager: FragmentHostManager
@Captor
lateinit var navigationModeCaptor: ArgumentCaptor<ModeChangedListener>
@Captor
@@ -77,6 +85,8 @@
lateinit var windowInsetsCallbackCaptor: ArgumentCaptor<Consumer<WindowInsets>>
@Captor
lateinit var constraintSetCaptor: ArgumentCaptor<ConstraintSet>
+ @Captor
+ lateinit var attachStateListenerCaptor: ArgumentCaptor<View.OnAttachStateChangeListener>
private lateinit var controller: NotificationsQSContainerController
private lateinit var navigationModeCallback: ModeChangedListener
@@ -91,8 +101,10 @@
mContext.ensureTestableResources()
whenever(notificationsQSContainer.context).thenReturn(mContext)
whenever(notificationsQSContainer.resources).thenReturn(mContext.resources)
+ whenever(fragmentService.getFragmentHostManager(any())).thenReturn(fragmentHostManager)
fakeSystemClock = FakeSystemClock()
delayableExecutor = FakeExecutor(fakeSystemClock)
+
controller = NotificationsQSContainerController(
notificationsQSContainer,
navigationModeController,
@@ -100,6 +112,7 @@
largeScreenShadeHeaderController,
shadeExpansionStateManager,
featureFlags,
+ fragmentService,
delayableExecutor
)
@@ -114,9 +127,10 @@
doNothing().`when`(notificationsQSContainer)
.setInsetsChangedListener(windowInsetsCallbackCaptor.capture())
doNothing().`when`(notificationsQSContainer).applyConstraints(constraintSetCaptor.capture())
-
+ doNothing().`when`(notificationsQSContainer)
+ .addOnAttachStateChangeListener(attachStateListenerCaptor.capture())
controller.init()
- controller.onViewAttached()
+ attachStateListenerCaptor.value.onViewAttachedToWindow(notificationsQSContainer)
navigationModeCallback = navigationModeCaptor.value
taskbarVisibilityCallback = taskbarVisibilityCaptor.value
@@ -385,6 +399,7 @@
largeScreenShadeHeaderController,
shadeExpansionStateManager,
featureFlags,
+ fragmentService,
delayableExecutor
)
controller.updateConstraints()
@@ -426,6 +441,17 @@
verify(largeScreenShadeHeaderController).startCustomizingAnimation(false, 100L)
}
+ @Test
+ fun testTagListenerAdded() {
+ verify(fragmentHostManager).addTagListener(eq(QS.TAG), eq(notificationsQSContainer))
+ }
+
+ @Test
+ fun testTagListenerRemoved() {
+ attachStateListenerCaptor.value.onViewDetachedFromWindow(notificationsQSContainer)
+ verify(fragmentHostManager).removeTagListener(eq(QS.TAG), eq(notificationsQSContainer))
+ }
+
private fun disableSplitShade() {
setSplitShadeEnabled(false)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 8aaa181..e68d3b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -45,6 +45,7 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import org.junit.After;
@@ -62,12 +63,14 @@
};
private CommandQueue mCommandQueue;
+
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private Callbacks mCallbacks;
private static final int SECONDARY_DISPLAY = 1;
@Before
public void setup() {
- mCommandQueue = new CommandQueue(mContext);
+ mCommandQueue = new CommandQueue(mContext, mDisplayTracker);
mCallbacks = mock(Callbacks.class);
mCommandQueue.addCallback(mCallbacks);
verify(mCallbacks).disable(anyInt(), eq(0), eq(0), eq(false));
@@ -415,7 +418,7 @@
@Test
public void testOnDisplayRemoved() {
- mCommandQueue.onDisplayRemoved(SECONDARY_DISPLAY);
+ mDisplayTracker.triggerOnDisplayRemoved(SECONDARY_DISPLAY);
waitForIdleSync();
verify(mCallbacks).onDisplayRemoved(eq(SECONDARY_DISPLAY));
}
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 610bb13..dffa566 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -58,6 +58,7 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.app.AlarmManager;
import android.app.Instrumentation;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyResourcesManager;
@@ -183,6 +184,8 @@
private ScreenLifecycle mScreenLifecycle;
@Mock
private AuthController mAuthController;
+ @Mock
+ private AlarmManager mAlarmManager;
@Captor
private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
@Captor
@@ -277,7 +280,9 @@
mAuthController, mLockPatternUtils, mScreenLifecycle,
mKeyguardBypassController, mAccessibilityManager,
mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
- mAlternateBouncerInteractor);
+ mAlternateBouncerInteractor,
+ mAlarmManager
+ );
mController.init();
mController.setIndicationArea(mIndicationArea);
verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 5124eb9..e6f272b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -37,6 +37,7 @@
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@@ -152,4 +153,18 @@
// and cause us to drop a frame during the LOCKSCREEN_TRANSITION_FROM_AOD CUJ.
assertEquals(0.99f, controller.dozeAmount, 0.009f)
}
+
+ @Test
+ fun testSetDreamState_invokesCallback() {
+ val listener = mock(StatusBarStateController.StateListener::class.java)
+ controller.addCallback(listener)
+
+ controller.setIsDreaming(true)
+ verify(listener).onDreamingChanged(true)
+
+ Mockito.clearInvocations(listener)
+
+ controller.setIsDreaming(false)
+ verify(listener).onDreamingChanged(false)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
index ea06647..a9c3d5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
@@ -6,6 +6,7 @@
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.FakeDisplayTracker
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -17,6 +18,7 @@
class GenericGestureDetectorTest : SysuiTestCase() {
private lateinit var gestureDetector: TestGestureDetector
+ private val displayTracker = FakeDisplayTracker(mContext)
@Before
fun setUp() {
@@ -101,12 +103,21 @@
gestureDetector.addOnGestureDetectedCallback("tag2"){}
gestureDetector.removeOnGestureDetectedCallback("tag")
- gestureDetector.onInputEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, CORRECT_X, 0f, 0))
+ gestureDetector.onInputEvent(
+ MotionEvent.obtain(
+ 0,
+ 0,
+ MotionEvent.ACTION_DOWN,
+ CORRECT_X,
+ 0f,
+ 0
+ )
+ )
assertThat(oldCallbackNotified).isFalse()
}
- inner class TestGestureDetector : GenericGestureDetector("fakeTag") {
+ inner class TestGestureDetector : GenericGestureDetector("fakeTag", displayTracker) {
var isGestureListening = false
override fun onInputEvent(ev: InputEvent) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 43b6e41..2423f13 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -34,6 +34,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceConfigPlugin
import com.android.systemui.plugins.BcSmartspaceDataPlugin
@@ -112,6 +113,9 @@
private lateinit var handler: Handler
@Mock
+ private lateinit var weatherPlugin: BcSmartspaceDataPlugin
+
+ @Mock
private lateinit var plugin: BcSmartspaceDataPlugin
@Mock
@@ -151,6 +155,7 @@
KeyguardBypassController.OnBypassStateChangedListener
private lateinit var deviceProvisionedListener: DeviceProvisionedListener
+ private lateinit var weatherSmartspaceView: SmartspaceView
private lateinit var smartspaceView: SmartspaceView
private val clock = FakeSystemClock()
@@ -176,16 +181,22 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
+ // Todo(b/261760571): flip the flag value here when feature is launched, and update relevant
+ // tests.
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(false)
+
`when`(secureSettings.getUriFor(PRIVATE_LOCKSCREEN_SETTING))
.thenReturn(fakePrivateLockscreenSettingUri)
`when`(secureSettings.getUriFor(NOTIF_ON_LOCKSCREEN_SETTING))
.thenReturn(fakeNotifOnLockscreenSettingUri)
`when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(smartspaceSession)
+ `when`(weatherPlugin.getView(any())).thenReturn(
+ createWeatherSmartspaceView(), createWeatherSmartspaceView())
`when`(plugin.getView(any())).thenReturn(createSmartspaceView(), createSmartspaceView())
`when`(userTracker.userProfiles).thenReturn(userList)
`when`(statusBarStateController.dozeAmount).thenReturn(0.5f)
- `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
- `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
setActiveUser(userHandlePrimary)
setAllowPrivateNotifications(userHandlePrimary, true)
@@ -210,6 +221,7 @@
executor,
bgExecutor,
handler,
+ Optional.of(weatherPlugin),
Optional.of(plugin),
Optional.of(configPlugin),
)
@@ -218,11 +230,22 @@
deviceProvisionedListener = deviceProvisionedCaptor.value
}
+ @Test(expected = RuntimeException::class)
+ fun testBuildAndConnectWeatherView_throwsIfDecouplingDisabled() {
+ // GIVEN the feature flag is disabled
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(false)
+
+ // WHEN we try to build the view
+ controller.buildAndConnectWeatherView(fakeParent)
+
+ // THEN an exception is thrown
+ }
+
@Test
- fun connectOnlyAfterDeviceIsProvisioned() {
+ fun testBuildAndConnectView_connectsOnlyAfterDeviceIsProvisioned() {
// GIVEN an unprovisioned device and an attempt to connect
- `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(false)
- `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(false)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(false)
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
// WHEN a connection attempt is made and view is attached
val view = controller.buildAndConnectView(fakeParent)
@@ -232,8 +255,8 @@
verify(smartspaceManager, never()).createSmartspaceSession(any())
// WHEN it does become provisioned
- `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
- `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
deviceProvisionedListener.onUserSetupChanged()
// THEN the session is created
@@ -243,7 +266,7 @@
}
@Test
- fun testListenersAreRegistered() {
+ fun testAddListener_registersListenersForPlugin() {
// GIVEN a listener is added after a session is created
connectSession()
@@ -252,10 +275,12 @@
// THEN the listener is registered to the underlying plugin
verify(plugin).registerListener(controllerListener)
+ // The listener is registered only for the plugin, not the weather plugin.
+ verify(weatherPlugin, never()).registerListener(any())
}
@Test
- fun testEarlyRegisteredListenersAreAttachedAfterConnected() {
+ fun testAddListener_earlyRegisteredListenersAreAttachedAfterConnected() {
// GIVEN a listener that is registered before the session is created
controller.addListener(controllerListener)
@@ -264,10 +289,12 @@
// THEN the listener is subsequently registered
verify(plugin).registerListener(controllerListener)
+ // The listener is registered only for the plugin, not the weather plugin.
+ verify(weatherPlugin, never()).registerListener(any())
}
@Test
- fun testEmptyListIsEmittedAndNotifierRemovedAfterDisconnect() {
+ fun testDisconnect_emitsEmptyListAndRemovesNotifier() {
// GIVEN a registered listener on an active session
connectSession()
clearInvocations(plugin)
@@ -279,10 +306,12 @@
// THEN the listener receives an empty list of targets and unregisters the notifier
verify(plugin).onTargetsAvailable(emptyList())
verify(plugin).registerSmartspaceEventNotifier(null)
+ verify(weatherPlugin).onTargetsAvailable(emptyList())
+ verify(weatherPlugin).registerSmartspaceEventNotifier(null)
}
@Test
- fun testUserChangeReloadsSmartspace() {
+ fun testUserChange_reloadsSmartspace() {
// GIVEN a connected smartspace session
connectSession()
@@ -294,7 +323,7 @@
}
@Test
- fun testSettingsChangeReloadsSmartspace() {
+ fun testSettingsChange_reloadsSmartspace() {
// GIVEN a connected smartspace session
connectSession()
@@ -306,7 +335,7 @@
}
@Test
- fun testThemeChangeUpdatesTextColor() {
+ fun testThemeChange_updatesTextColor() {
// GIVEN a connected smartspace session
connectSession()
@@ -318,7 +347,22 @@
}
@Test
- fun testDozeAmountChangeUpdatesView() {
+ fun testThemeChange_ifDecouplingEnabled_updatesTextColor() {
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
+
+ // GIVEN a connected smartspace session
+ connectSession()
+
+ // WHEN the theme changes
+ configChangeListener.onThemeChanged()
+
+ // We update the new text color to match the wallpaper color
+ verify(weatherSmartspaceView).setPrimaryTextColor(anyInt())
+ verify(smartspaceView).setPrimaryTextColor(anyInt())
+ }
+
+ @Test
+ fun testDozeAmountChange_updatesView() {
// GIVEN a connected smartspace session
connectSession()
@@ -330,7 +374,22 @@
}
@Test
- fun testKeyguardBypassEnabledUpdatesView() {
+ fun testDozeAmountChange_ifDecouplingEnabled_updatesViews() {
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
+
+ // GIVEN a connected smartspace session
+ connectSession()
+
+ // WHEN the doze amount changes
+ statusBarStateListener.onDozeAmountChanged(0.1f, 0.7f)
+
+ // We pass that along to the view
+ verify(weatherSmartspaceView).setDozeAmount(0.7f)
+ verify(smartspaceView).setDozeAmount(0.7f)
+ }
+
+ @Test
+ fun testKeyguardBypassEnabled_updatesView() {
// GIVEN a connected smartspace session
connectSession()
`when`(keyguardBypassController.bypassEnabled).thenReturn(true)
@@ -425,6 +484,27 @@
}
@Test
+ fun testSessionListener_ifDecouplingEnabled_weatherTargetIsFilteredOut() {
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
+ connectSession()
+
+ // WHEN we receive a list of targets
+ val targets = listOf(
+ makeTarget(1, userHandlePrimary, isSensitive = true),
+ makeTarget(2, userHandlePrimary),
+ makeTarget(3, userHandleManaged),
+ makeTarget(4, userHandlePrimary, featureType = SmartspaceTarget.FEATURE_WEATHER)
+ )
+
+ sessionListener.onTargetsAvailable(targets)
+
+ // THEN all non-sensitive content is still shown
+ verify(plugin).onTargetsAvailable(eq(listOf(targets[0], targets[1], targets[2])))
+ // No filtering is applied for the weather plugin
+ verify(weatherPlugin).onTargetsAvailable(eq(targets))
+ }
+
+ @Test
fun testSettingsAreReloaded() {
// GIVEN a connected session where the privacy settings later flip to false
connectSession()
@@ -515,6 +595,16 @@
}
@Test
+ fun testWeatherViewUsesSameSession() {
+ `when`(featureFlags.isEnabled(Flags.SMARTSPACE_DATE_WEATHER_DECOUPLED)).thenReturn(true)
+ // GIVEN a connected session
+ connectSession()
+
+ // No checks is needed here, since connectSession() already checks internally that
+ // createSmartspaceSession is invoked only once.
+ }
+
+ @Test
fun testViewGetInitializedWithBypassEnabledState() {
// GIVEN keyguard bypass is enabled.
`when`(keyguardBypassController.bypassEnabled).thenReturn(true)
@@ -531,8 +621,8 @@
fun testConnectAttemptBeforeInitializationShouldNotCreateSession() {
// GIVEN an uninitalized smartspaceView
// WHEN the device is provisioned
- `when`(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true)
- `when`(deviceProvisionedController.isCurrentUserSetup()).thenReturn(true)
+ `when`(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+ `when`(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
deviceProvisionedListener.onDeviceProvisionedChanged()
// THEN no calls to createSmartspaceSession should occur
@@ -542,9 +632,23 @@
}
private fun connectSession() {
+ if (controller.isDateWeatherDecoupled()) {
+ val weatherView = controller.buildAndConnectWeatherView(fakeParent)
+ weatherSmartspaceView = weatherView as SmartspaceView
+ fakeParent.addView(weatherView)
+ controller.stateChangeListener.onViewAttachedToWindow(weatherView)
+
+ verify(weatherSmartspaceView).setUiSurface(
+ BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
+ verify(weatherSmartspaceView).registerDataProvider(weatherPlugin)
+
+ verify(weatherSmartspaceView).setPrimaryTextColor(anyInt())
+ verify(weatherSmartspaceView).setDozeAmount(0.5f)
+ }
+
val view = controller.buildAndConnectView(fakeParent)
smartspaceView = view as SmartspaceView
-
+ fakeParent.addView(view)
controller.stateChangeListener.onViewAttachedToWindow(view)
verify(smartspaceView).setUiSurface(BcSmartspaceDataPlugin.UI_SURFACE_LOCK_SCREEN_AOD)
@@ -554,6 +658,8 @@
.addOnTargetsAvailableListener(any(), capture(sessionListenerCaptor))
sessionListener = sessionListenerCaptor.value
+ verify(smartspaceManager).createSmartspaceSession(any())
+
verify(userTracker).addCallback(capture(userTrackerCaptor), any())
userListener = userTrackerCaptor.value
@@ -578,9 +684,11 @@
verify(smartspaceView).setPrimaryTextColor(anyInt())
verify(smartspaceView).setDozeAmount(0.5f)
- clearInvocations(view)
- fakeParent.addView(view)
+ if (controller.isDateWeatherDecoupled()) {
+ clearInvocations(weatherSmartspaceView)
+ }
+ clearInvocations(smartspaceView)
}
private fun setActiveUser(userHandle: UserHandle) {
@@ -626,6 +734,31 @@
).thenReturn(if (value) 1 else 0)
}
+ // Separate function for the weather view, which doesn't implement all functions in interface.
+ private fun createWeatherSmartspaceView(): SmartspaceView {
+ return spy(object : View(context), SmartspaceView {
+ override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
+ }
+
+ override fun setPrimaryTextColor(color: Int) {
+ }
+
+ override fun setIsDreaming(isDreaming: Boolean) {
+ }
+
+ override fun setUiSurface(uiSurface: String) {
+ }
+
+ override fun setDozeAmount(amount: Float) {
+ }
+
+ override fun setIntentStarter(intentStarter: BcSmartspaceDataPlugin.IntentStarter?) {
+ }
+
+ override fun setFalsingManager(falsingManager: FalsingManager?) {
+ }
+ })
+ }
private fun createSmartspaceView(): SmartspaceView {
return spy(object : View(context), SmartspaceView {
override fun registerDataProvider(plugin: BcSmartspaceDataPlugin?) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index b6a1bb3..d7ac6b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -66,9 +66,9 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -133,18 +133,13 @@
@Mock private ShadeController mShadeController;
@Mock private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
@Mock private AssistantFeedbackController mAssistantFeedbackController;
+ @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
+ @Mock private StatusBarStateController mStatusBarStateController;
@Before
public void setUp() {
mTestableLooper = TestableLooper.get(this);
allowTestableLooperAsMainThread();
- mDependency.injectTestDependency(DeviceProvisionedController.class,
- mDeviceProvisionedController);
- mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
- mDependency.injectTestDependency(
- OnUserInteractionCallback.class,
- mOnUserInteractionCallback);
- mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
mHandler = Handler.createAsync(mTestableLooper.getLooper());
mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
@@ -155,7 +150,11 @@
mPeopleSpaceWidgetManager, mLauncherApps, mShortcutManager,
mChannelEditorDialogController, mContextTracker, mAssistantFeedbackController,
Optional.of(mBubblesManager), new UiEventLoggerFake(), mOnUserInteractionCallback,
- mShadeController);
+ mShadeController,
+ mNotificationLockscreenUserManager,
+ mStatusBarStateController,
+ mDeviceProvisionedController,
+ mMetricsLogger);
mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
mOnSettingsClickListener);
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -372,7 +371,8 @@
eq(false),
eq(false),
eq(true), /* wasShownHighPriority */
- eq(mAssistantFeedbackController));
+ eq(mAssistantFeedbackController),
+ any(MetricsLogger.class));
}
@Test
@@ -406,7 +406,8 @@
eq(true),
eq(false),
eq(false), /* wasShownHighPriority */
- eq(mAssistantFeedbackController));
+ eq(mAssistantFeedbackController),
+ any(MetricsLogger.class));
}
@Test
@@ -438,7 +439,8 @@
eq(false),
eq(false),
eq(false), /* wasShownHighPriority */
- eq(mAssistantFeedbackController));
+ eq(mAssistantFeedbackController),
+ any(MetricsLogger.class));
}
////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 80a81a5..8dd0488 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -130,7 +130,6 @@
mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
- mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
// Inflate the layout
final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info,
@@ -194,7 +193,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -220,7 +220,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final ImageView iconView = mNotificationInfo.findViewById(R.id.pkg_icon);
assertEquals(iconDrawable, iconView.getDrawable());
}
@@ -242,7 +243,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
}
@@ -273,7 +275,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(VISIBLE, nameView.getVisibility());
assertTrue(nameView.getText().toString().contains("Proxied"));
@@ -296,7 +299,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
}
@@ -324,7 +328,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
@@ -347,7 +352,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(TEST_CHANNEL_NAME, textView.getText());
}
@@ -369,7 +375,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, textView.getVisibility());
}
@@ -395,7 +402,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@@ -417,7 +425,8 @@
true,
true,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(VISIBLE, textView.getVisibility());
}
@@ -443,7 +452,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
@@ -468,7 +478,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -493,7 +504,8 @@
false,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -515,7 +527,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
@@ -531,7 +544,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertEquals(View.VISIBLE, settingsButton.getVisibility());
}
@@ -556,7 +570,8 @@
true,
true,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.info).performClick();
// Verify that listener was triggered.
@@ -582,7 +597,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView channelNameView =
mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, channelNameView.getVisibility());
@@ -606,7 +622,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(GONE, mNotificationInfo.findViewById(
R.id.interruptiveness_settings).getVisibility());
assertEquals(VISIBLE, mNotificationInfo.findViewById(
@@ -630,7 +647,8 @@
true,
true,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.notification_unblockable_desc),
@@ -673,7 +691,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_call_text);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.notification_unblockable_call_desc),
@@ -716,7 +735,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(GONE,
mNotificationInfo.findViewById(R.id.non_configurable_call_text).getVisibility());
assertEquals(VISIBLE,
@@ -743,7 +763,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.automatic).getVisibility());
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.automatic_summary).getVisibility());
}
@@ -765,7 +786,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(GONE, mNotificationInfo.findViewById(R.id.automatic).getVisibility());
assertEquals(GONE, mNotificationInfo.findViewById(R.id.automatic_summary).getVisibility());
}
@@ -789,7 +811,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertTrue(mNotificationInfo.findViewById(R.id.automatic).isSelected());
}
@@ -810,7 +833,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertTrue(mNotificationInfo.findViewById(R.id.alert).isSelected());
}
@@ -831,7 +855,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertTrue(mNotificationInfo.findViewById(R.id.silence).isSelected());
}
@@ -852,7 +877,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
@@ -875,7 +901,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(1, mUiEventLogger.numLogs());
assertEquals(NotificationControlsEvent.NOTIFICATION_CONTROLS_OPEN.getId(),
mUiEventLogger.eventId(0));
@@ -899,7 +926,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.alert).performClick();
mTestableLooper.processAllMessages();
@@ -926,7 +954,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.silence).performClick();
mTestableLooper.processAllMessages();
@@ -953,7 +982,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.automatic).performClick();
mTestableLooper.processAllMessages();
@@ -981,7 +1011,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1008,7 +1039,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1043,7 +1075,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.handleCloseControls(true, false);
@@ -1071,7 +1104,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.silence).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1112,7 +1146,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.alert).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1149,7 +1184,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.automatic).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1181,7 +1217,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.silence).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1217,7 +1254,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(mContext.getString(R.string.inline_done_button),
((TextView) mNotificationInfo.findViewById(R.id.done)).getText());
@@ -1255,7 +1293,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.silence).performClick();
mNotificationInfo.handleCloseControls(false, false);
@@ -1286,7 +1325,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(mContext.getString(R.string.inline_done_button),
((TextView) mNotificationInfo.findViewById(R.id.done)).getText());
@@ -1324,7 +1364,8 @@
true,
false,
true,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.silence).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1353,7 +1394,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertEquals(mContext.getString(R.string.inline_done_button),
((TextView) mNotificationInfo.findViewById(R.id.done)).getText());
@@ -1384,7 +1426,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.alert).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1419,7 +1462,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.alert).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1452,7 +1496,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.alert).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -1485,7 +1530,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1511,7 +1557,8 @@
true,
false,
false,
- mAssistantFeedbackController);
+ mAssistantFeedbackController,
+ mMetricsLogger);
assertFalse(mNotificationInfo.willBeRemoved());
}
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 b1363a0..0605398 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
@@ -1010,6 +1010,18 @@
}
@Test
+ public void testSetDozingNotUnlocking_transitionToAOD_cancelKeyguardFadingAway() {
+ setDozing(true);
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+ when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true);
+
+ mCentralSurfaces.updateScrimController();
+
+ verify(mScrimController, times(2)).transitionTo(eq(ScrimState.AOD));
+ verify(mStatusBarKeyguardViewManager).onKeyguardFadedAway();
+ }
+
+ @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
deleted file mode 100644
index 2f49535..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyFloat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.hardware.biometrics.BiometricSourceType;
-import android.os.Handler;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.keyguard.KeyguardHostViewController;
-import com.android.keyguard.KeyguardSecurityModel;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.dagger.KeyguardBouncerComponent;
-import com.android.systemui.DejankUtils;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.keyguard.DismissCallbackRegistry;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class KeyguardBouncerTest extends SysuiTestCase {
-
- @Mock
- private FalsingCollector mFalsingCollector;
- @Mock
- private ViewMediatorCallback mViewMediatorCallback;
- @Mock
- private DismissCallbackRegistry mDismissCallbackRegistry;
- @Mock
- private KeyguardHostViewController mKeyguardHostViewController;
- @Mock
- private PrimaryBouncerExpansionCallback mExpansionCallback;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- private KeyguardBypassController mKeyguardBypassController;
- @Mock
- private Handler mHandler;
- @Mock
- private KeyguardSecurityModel mKeyguardSecurityModel;
- @Mock
- private KeyguardBouncerComponent.Factory mKeyguardBouncerComponentFactory;
- @Mock
- private KeyguardBouncerComponent mKeyguardBouncerComponent;
- private ViewGroup mContainer;
- @Rule
- public MockitoRule mRule = MockitoJUnit.rule();
- private Integer mRootVisibility = View.INVISIBLE;
- private KeyguardBouncer mBouncer;
-
- @Before
- public void setup() {
- allowTestableLooperAsMainThread();
- when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
- .thenReturn(KeyguardSecurityModel.SecurityMode.None);
- DejankUtils.setImmediate(true);
-
- mContainer = spy(new FrameLayout(getContext()));
- when(mKeyguardBouncerComponentFactory.create(mContainer)).thenReturn(
- mKeyguardBouncerComponent);
- when(mKeyguardBouncerComponent.getKeyguardHostViewController())
- .thenReturn(mKeyguardHostViewController);
-
- mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback,
- mDismissCallbackRegistry, mFalsingCollector,
- mKeyguardStateController, mKeyguardUpdateMonitor,
- mKeyguardBypassController, mHandler, mKeyguardSecurityModel,
- mKeyguardBouncerComponentFactory)
- .create(mContainer, mExpansionCallback);
- }
-
- @Test
- public void testInflateView_doesntCrash() {
- mBouncer.inflateView();
- }
-
- @Test
- public void testShow_notifiesFalsingManager() {
- mBouncer.show(true);
- verify(mFalsingCollector).onBouncerShown();
-
- mBouncer.show(true, false);
- verifyNoMoreInteractions(mFalsingCollector);
- }
-
- /**
- * Regression test: Invisible bouncer when occluded.
- */
- @Test
- public void testShow_bouncerIsVisible() {
- // Expand notification panel as if we were in the keyguard.
- mBouncer.ensureView();
- mBouncer.setExpansion(1);
-
- reset(mKeyguardHostViewController);
-
- mBouncer.show(true);
- verify(mKeyguardHostViewController).setExpansion(0);
- }
-
- @Test
- public void testShow_notifiesVisibility() {
- mBouncer.show(true);
- verify(mKeyguardStateController).notifyBouncerShowing(eq(true));
- verify(mExpansionCallback).onStartingToShow();
-
- // Not called again when visible
- reset(mViewMediatorCallback);
- mBouncer.show(true);
- verifyNoMoreInteractions(mViewMediatorCallback);
- }
-
- @Test
- public void testShow_triesToDismissKeyguard() {
- mBouncer.show(true);
- verify(mKeyguardHostViewController).dismiss(anyInt());
- }
-
- @Test
- public void testShow_resetsSecuritySelection() {
- mBouncer.show(false);
- verify(mKeyguardHostViewController, never()).showPrimarySecurityScreen();
-
- mBouncer.hide(false);
- mBouncer.show(true);
- verify(mKeyguardHostViewController).showPrimarySecurityScreen();
- }
-
- @Test
- public void testShow_animatesKeyguardView() {
- mBouncer.show(true);
- verify(mKeyguardHostViewController).appear(anyInt());
- }
-
- @Test
- public void testShow_showsErrorMessage() {
- final String errorMessage = "an error message";
- when(mViewMediatorCallback.consumeCustomMessage()).thenReturn(errorMessage);
- mBouncer.show(true);
- verify(mKeyguardHostViewController).showErrorMessage(eq(errorMessage));
- }
-
- @Test
- public void testSetExpansion_notifiesFalsingManager() {
- mBouncer.ensureView();
- mBouncer.setExpansion(0.5f);
-
- mBouncer.setExpansion(EXPANSION_HIDDEN);
- verify(mFalsingCollector).onBouncerHidden();
- verify(mExpansionCallback).onFullyHidden();
-
- mBouncer.setExpansion(EXPANSION_VISIBLE);
- verify(mFalsingCollector).onBouncerShown();
- verify(mExpansionCallback).onFullyShown();
-
- verify(mExpansionCallback, never()).onStartingToHide();
- verify(mKeyguardHostViewController, never()).onStartingToHide();
- mBouncer.setExpansion(0.9f);
- verify(mExpansionCallback).onStartingToHide();
- verify(mKeyguardHostViewController).onStartingToHide();
- }
-
- @Test
- public void testSetExpansion_notifiesKeyguardView() {
- mBouncer.ensureView();
- mBouncer.setExpansion(0.1f);
-
- mBouncer.setExpansion(0);
- verify(mKeyguardHostViewController).onResume();
- verify(mContainer).announceForAccessibility(any());
- }
-
- @Test
- public void show_notifiesKeyguardViewController() {
- mBouncer.ensureView();
-
- mBouncer.show(/* resetSecuritySelection= */ false);
-
- verify(mKeyguardHostViewController).onBouncerVisibilityChanged(View.VISIBLE);
- }
-
- @Test
- public void testHide_notifiesFalsingManager() {
- mBouncer.hide(false);
- verify(mFalsingCollector).onBouncerHidden();
- }
-
- @Test
- public void testHide_notifiesVisibility() {
- mBouncer.hide(false);
- verify(mKeyguardStateController).notifyBouncerShowing(eq(false));
- }
-
- @Test
- public void testHide_notifiesDismissCallbackIfVisible() {
- mBouncer.hide(false);
- verifyZeroInteractions(mDismissCallbackRegistry);
- mBouncer.show(false);
- mBouncer.hide(false);
- verify(mDismissCallbackRegistry).notifyDismissCancelled();
- }
-
- @Test
- public void testHide_notShowingAnymore() {
- mBouncer.ensureView();
- mBouncer.show(false /* resetSecuritySelection */);
- mBouncer.hide(false /* destroyViews */);
- Assert.assertFalse("Not showing", mBouncer.isShowing());
- }
-
- @Test
- public void testShowPromptReason_propagates() {
- mBouncer.ensureView();
- mBouncer.showPromptReason(1);
- verify(mKeyguardHostViewController).showPromptReason(eq(1));
- }
-
- @Test
- public void testShowMessage_propagates() {
- final String message = "a message";
- mBouncer.ensureView();
- mBouncer.showMessage(message, ColorStateList.valueOf(Color.GREEN));
- verify(mKeyguardHostViewController).showMessage(
- eq(message), eq(ColorStateList.valueOf(Color.GREEN)));
- }
-
- @Test
- public void testShowOnDismissAction_showsBouncer() {
- final OnDismissAction dismissAction = () -> false;
- final Runnable cancelAction = () -> {};
- mBouncer.showWithDismissAction(dismissAction, cancelAction);
- verify(mKeyguardHostViewController).setOnDismissAction(dismissAction, cancelAction);
- Assert.assertTrue("Should be showing", mBouncer.isShowing());
- }
-
- @Test
- public void testStartPreHideAnimation_notifiesView() {
- final boolean[] ran = {false};
- final Runnable r = () -> ran[0] = true;
- mBouncer.startPreHideAnimation(r);
- Assert.assertTrue("Callback should have been invoked", ran[0]);
-
- ran[0] = false;
- mBouncer.ensureView();
- mBouncer.startPreHideAnimation(r);
- verify(mKeyguardHostViewController).startDisappearAnimation(r);
- Assert.assertFalse("Callback should have been deferred", ran[0]);
- }
-
- @Test
- public void testIsShowing_animated() {
- Assert.assertFalse("Show wasn't invoked yet", mBouncer.isShowing());
- mBouncer.show(true /* reset */);
- Assert.assertTrue("Should be showing", mBouncer.isShowing());
- }
-
- @Test
- public void testIsShowing_forSwipeUp() {
- mBouncer.setExpansion(1f);
- mBouncer.show(true /* reset */, false /* animated */);
- Assert.assertFalse("Should only be showing after collapsing notification panel",
- mBouncer.isShowing());
- mBouncer.setExpansion(0f);
- Assert.assertTrue("Should be showing", mBouncer.isShowing());
- }
-
- @Test
- public void testSetExpansion() {
- mBouncer.ensureView();
- mBouncer.setExpansion(0.5f);
- verify(mKeyguardHostViewController).setExpansion(0.5f);
- }
-
- @Test
- public void testIsFullscreenBouncer_asksKeyguardView() {
- mBouncer.ensureView();
- mBouncer.isFullscreenBouncer();
- verify(mKeyguardHostViewController).getCurrentSecurityMode();
- }
-
- @Test
- public void testIsHiding_preHideOrHide() {
- Assert.assertFalse("Should not be hiding on initial state", mBouncer.isAnimatingAway());
- mBouncer.startPreHideAnimation(null /* runnable */);
- Assert.assertTrue("Should be hiding during pre-hide", mBouncer.isAnimatingAway());
- mBouncer.hide(false /* destroyView */);
- Assert.assertFalse("Should be hidden after hide()", mBouncer.isAnimatingAway());
- }
-
- @Test
- public void testIsHiding_skipsTranslation() {
- mBouncer.show(false /* reset */);
- reset(mKeyguardHostViewController);
- mBouncer.startPreHideAnimation(null /* runnable */);
- mBouncer.setExpansion(0.5f);
- verify(mKeyguardHostViewController, never()).setExpansion(anyFloat());
- }
-
- @Test
- public void testIsSecure() {
- mBouncer.ensureView();
- for (KeyguardSecurityModel.SecurityMode mode : KeyguardSecurityModel.SecurityMode.values()){
- reset(mKeyguardSecurityModel);
- when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(mode);
- Assert.assertEquals("Security doesn't match for mode: " + mode,
- mBouncer.isSecure(), mode != KeyguardSecurityModel.SecurityMode.None);
- }
- }
-
- @Test
- public void testIsShowingScrimmed_true() {
- doAnswer(invocation -> {
- assertThat(mBouncer.isScrimmed()).isTrue();
- return null;
- }).when(mExpansionCallback).onFullyShown();
- mBouncer.show(false /* resetSecuritySelection */, true /* animate */);
- assertThat(mBouncer.isScrimmed()).isTrue();
- mBouncer.hide(false /* destroyView */);
- assertThat(mBouncer.isScrimmed()).isFalse();
- }
-
- @Test
- public void testIsShowingScrimmed_false() {
- doAnswer(invocation -> {
- assertThat(mBouncer.isScrimmed()).isFalse();
- return null;
- }).when(mExpansionCallback).onFullyShown();
- mBouncer.show(false /* resetSecuritySelection */, false /* animate */);
- assertThat(mBouncer.isScrimmed()).isFalse();
- }
-
- @Test
- public void testWillDismissWithAction() {
- mBouncer.ensureView();
- Assert.assertFalse("Action not set yet", mBouncer.willDismissWithAction());
- when(mKeyguardHostViewController.hasDismissActions()).thenReturn(true);
- Assert.assertTrue("Action should exist", mBouncer.willDismissWithAction());
- }
-
- @Test
- public void testShow_delaysIfFaceAuthIsRunning() {
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
- .thenReturn(true);
- when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
- mBouncer.show(true /* reset */);
-
- ArgumentCaptor<Runnable> showRunnable = ArgumentCaptor.forClass(Runnable.class);
- verify(mHandler).postDelayed(showRunnable.capture(),
- eq(KeyguardBouncer.BOUNCER_FACE_DELAY));
-
- mBouncer.hide(false /* destroyView */);
- verify(mHandler).removeCallbacks(eq(showRunnable.getValue()));
- }
-
- @Test
- public void testShow_doesNotDelaysIfFaceAuthIsNotAllowed() {
- when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
- .thenReturn(false);
- mBouncer.show(true /* reset */);
-
- verify(mHandler, never()).postDelayed(any(), anyLong());
- }
-
- @Test
- public void testShow_delaysIfFaceAuthIsRunning_unlessBypassEnabled() {
- when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
- when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
- mBouncer.show(true /* reset */);
-
- verify(mHandler, never()).postDelayed(any(), anyLong());
- }
-
- @Test
- public void testShow_delaysIfFaceAuthIsRunning_unlessFingerprintEnrolled() {
- when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
- when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0))
- .thenReturn(true);
- mBouncer.show(true /* reset */);
-
- verify(mHandler, never()).postDelayed(any(), anyLong());
- }
-
- @Test
- public void testRegisterUpdateMonitorCallback() {
- verify(mKeyguardUpdateMonitor).registerCallback(any());
- }
-
- @Test
- public void testInTransit_whenTranslation() {
- mBouncer.show(true);
- mBouncer.setExpansion(EXPANSION_HIDDEN);
- assertThat(mBouncer.inTransit()).isFalse();
- mBouncer.setExpansion(0.5f);
- assertThat(mBouncer.inTransit()).isTrue();
- mBouncer.setExpansion(EXPANSION_VISIBLE);
- assertThat(mBouncer.inTransit()).isFalse();
- }
-
- @Test
- public void testUpdateResources_delegatesToRootView() {
- mBouncer.ensureView();
- mBouncer.updateResources();
-
- // This is mocked, so won't pick up on the call to updateResources via
- // mKeyguardViewController.init(), only updateResources above.
- verify(mKeyguardHostViewController).updateResources();
- }
-
- @Test
- public void testUpdateKeyguardPosition_delegatesToRootView() {
- mBouncer.ensureView();
- mBouncer.updateKeyguardPosition(1.0f);
-
- verify(mKeyguardHostViewController).updateKeyguardPosition(1.0f);
- }
-
- @Test
- public void testExpansion_notifiesCallback() {
- mBouncer.ensureView();
- mBouncer.setExpansion(0.5f);
-
- final PrimaryBouncerExpansionCallback callback =
- mock(PrimaryBouncerExpansionCallback.class);
- mBouncer.addBouncerExpansionCallback(callback);
-
- mBouncer.setExpansion(EXPANSION_HIDDEN);
- verify(callback).onFullyHidden();
- verify(callback).onExpansionChanged(EXPANSION_HIDDEN);
-
- Mockito.clearInvocations(callback);
- mBouncer.setExpansion(EXPANSION_VISIBLE);
- verify(callback).onFullyShown();
- verify(callback).onExpansionChanged(EXPANSION_VISIBLE);
-
- Mockito.clearInvocations(callback);
- float bouncerHideAmount = 0.9f;
- // Ensure the callback only triggers once despite multiple calls to setExpansion
- // with the same value.
- mBouncer.setExpansion(bouncerHideAmount);
- mBouncer.setExpansion(bouncerHideAmount);
- verify(callback, times(1)).onStartingToHide();
- verify(callback, times(1)).onExpansionChanged(bouncerHideAmount);
-
- Mockito.clearInvocations(callback);
- mBouncer.removeBouncerExpansionCallback(callback);
- bouncerHideAmount = 0.5f;
- mBouncer.setExpansion(bouncerHideAmount);
- verify(callback, never()).onExpansionChanged(bouncerHideAmount);
- }
-
- @Test
- public void testOnResumeCalledForFullscreenBouncerOnSecondShow() {
- // GIVEN a security mode which requires fullscreen bouncer
- when(mKeyguardSecurityModel.getSecurityMode(anyInt()))
- .thenReturn(KeyguardSecurityModel.SecurityMode.SimPin);
- mBouncer.show(true);
-
- // WHEN a second call to show occurs, the bouncer will already by visible
- reset(mKeyguardHostViewController);
- mBouncer.show(true);
-
- // THEN ensure the ViewController is told to resume
- verify(mKeyguardHostViewController).onResume();
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index cc4abfc..529519a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -38,6 +38,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.policy.BatteryController;
import org.junit.Before;
@@ -67,7 +68,8 @@
mStatusBarIconController,
mock(BatteryController.class),
mock(NavigationModeController.class),
- mock(DumpManager.class));
+ mock(DumpManager.class),
+ new FakeDisplayTracker(mContext));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
index 189aa0f..0a68406 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarTransitionsControllerTest.java
@@ -28,6 +28,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.LightBarTransitionsController.DarkIntensityApplier;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -56,7 +57,8 @@
public void setup() {
MockitoAnnotations.initMocks(this);
mLightBarTransitionsController = new LightBarTransitionsController(mContext, mApplier,
- new CommandQueue(mContext), mKeyguardStateController, mStatusBarStateController);
+ new CommandQueue(mContext, new FakeDisplayTracker(mContext)),
+ mKeyguardStateController, mStatusBarStateController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 1ba0a36..d8446f4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static com.android.systemui.flags.Flags.MODERN_BOUNCER;
import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
@@ -109,7 +108,6 @@
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private View mNotificationContainer;
@Mock private KeyguardBypassController mBypassController;
- @Mock private KeyguardBouncer.Factory mKeyguardBouncerFactory;
@Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
@Mock private KeyguardMessageAreaController mKeyguardMessageAreaController;
@Mock private KeyguardMessageArea mKeyguardMessageArea;
@@ -153,8 +151,6 @@
.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_BOUNCER_ANIM))
.thenReturn(true);
- when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(true);
-
mStatusBarKeyguardViewManager =
new StatusBarKeyguardViewManager(
getContext(),
@@ -169,7 +165,6 @@
mock(NotificationShadeWindowController.class),
mKeyguardStateController,
mock(NotificationMediaManager.class),
- mKeyguardBouncerFactory,
mKeyguardMessageAreaFactory,
Optional.of(mSysUiUnfoldComponent),
() -> mShadeController,
@@ -660,7 +655,6 @@
mock(NotificationShadeWindowController.class),
mKeyguardStateController,
mock(NotificationMediaManager.class),
- mKeyguardBouncerFactory,
mKeyguardMessageAreaFactory,
Optional.of(mSysUiUnfoldComponent),
() -> mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
deleted file mode 100644
index 55ab681..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest_Old.java
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.systemui.flags.Flags.MODERN_BOUNCER;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
-import static com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyFloat;
-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.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewRootImpl;
-import android.window.OnBackInvokedCallback;
-import android.window.OnBackInvokedDispatcher;
-import android.window.WindowOnBackInvokedDispatcher;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardMessageArea;
-import com.android.keyguard.KeyguardMessageAreaController;
-import com.android.keyguard.KeyguardSecurityModel;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dock.DockManager;
-import com.android.systemui.dreams.DreamOverlayStateController;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.keyguard.data.BouncerView;
-import com.android.systemui.keyguard.data.BouncerViewDelegate;
-import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback;
-import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
-import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.shade.NotificationPanelViewController;
-import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.ShadeExpansionChangeEvent;
-import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
-
-import com.google.common.truth.Truth;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Optional;
-
-/**
- * StatusBarKeyguardViewManager Test with deprecated KeyguardBouncer.java.
- * TODO: Delete when deleting {@link KeyguardBouncer}
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class StatusBarKeyguardViewManagerTest_Old extends SysuiTestCase {
- private static final ShadeExpansionChangeEvent EXPANSION_EVENT =
- expansionEvent(/* fraction= */ 0.5f, /* expanded= */ false, /* tracking= */ true);
-
- @Mock private ViewMediatorCallback mViewMediatorCallback;
- @Mock private LockPatternUtils mLockPatternUtils;
- @Mock private CentralSurfaces mCentralSurfaces;
- @Mock private ViewGroup mContainer;
- @Mock private NotificationPanelViewController mNotificationPanelView;
- @Mock private BiometricUnlockController mBiometricUnlockController;
- @Mock private SysuiStatusBarStateController mStatusBarStateController;
- @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock private View mNotificationContainer;
- @Mock private KeyguardBypassController mBypassController;
- @Mock private KeyguardBouncer.Factory mKeyguardBouncerFactory;
- @Mock private KeyguardMessageAreaController.Factory mKeyguardMessageAreaFactory;
- @Mock private KeyguardMessageAreaController mKeyguardMessageAreaController;
- @Mock private KeyguardBouncer mPrimaryBouncer;
- @Mock private KeyguardMessageArea mKeyguardMessageArea;
- @Mock private ShadeController mShadeController;
- @Mock private SysUIUnfoldComponent mSysUiUnfoldComponent;
- @Mock private DreamOverlayStateController mDreamOverlayStateController;
- @Mock private LatencyTracker mLatencyTracker;
- @Mock private FeatureFlags mFeatureFlags;
- @Mock private KeyguardSecurityModel mKeyguardSecurityModel;
- @Mock private PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
- @Mock private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
- @Mock private AlternateBouncerInteractor mAlternateBouncerInteractor;
- @Mock private BouncerView mBouncerView;
- @Mock private BouncerViewDelegate mBouncerViewDelegate;
-
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- private PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
- mBouncerExpansionCallback;
- private FakeKeyguardStateController mKeyguardStateController =
- spy(new FakeKeyguardStateController());
-
- @Mock private ViewRootImpl mViewRootImpl;
- @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
- @Captor
- private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
-
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mKeyguardBouncerFactory.create(
- any(ViewGroup.class),
- any(PrimaryBouncerExpansionCallback.class)))
- .thenReturn(mPrimaryBouncer);
- when(mCentralSurfaces.getBouncerContainer()).thenReturn(mContainer);
- when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea);
- when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
- .thenReturn(mKeyguardMessageAreaController);
- when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
-
- mStatusBarKeyguardViewManager =
- new StatusBarKeyguardViewManager(
- getContext(),
- mViewMediatorCallback,
- mLockPatternUtils,
- mStatusBarStateController,
- mock(ConfigurationController.class),
- mKeyguardUpdateMonitor,
- mDreamOverlayStateController,
- mock(NavigationModeController.class),
- mock(DockManager.class),
- mock(NotificationShadeWindowController.class),
- mKeyguardStateController,
- mock(NotificationMediaManager.class),
- mKeyguardBouncerFactory,
- mKeyguardMessageAreaFactory,
- Optional.of(mSysUiUnfoldComponent),
- () -> mShadeController,
- mLatencyTracker,
- mKeyguardSecurityModel,
- mFeatureFlags,
- mPrimaryBouncerCallbackInteractor,
- mPrimaryBouncerInteractor,
- mBouncerView,
- mAlternateBouncerInteractor) {
- @Override
- public ViewRootImpl getViewRootImpl() {
- return mViewRootImpl;
- }
- };
- when(mViewRootImpl.getOnBackInvokedDispatcher())
- .thenReturn(mOnBackInvokedDispatcher);
- mStatusBarKeyguardViewManager.registerCentralSurfaces(
- mCentralSurfaces,
- mNotificationPanelView,
- new ShadeExpansionStateManager(),
- mBiometricUnlockController,
- mNotificationContainer,
- mBypassController);
- mStatusBarKeyguardViewManager.show(null);
- ArgumentCaptor<PrimaryBouncerExpansionCallback> callbackArgumentCaptor =
- ArgumentCaptor.forClass(PrimaryBouncerExpansionCallback.class);
- verify(mKeyguardBouncerFactory).create(any(ViewGroup.class),
- callbackArgumentCaptor.capture());
- mBouncerExpansionCallback = callbackArgumentCaptor.getValue();
- }
-
- @Test
- public void dismissWithAction_AfterKeyguardGoneSetToFalse() {
- OnDismissAction action = () -> false;
- Runnable cancelAction = () -> {};
- mStatusBarKeyguardViewManager.dismissWithAction(
- action, cancelAction, false /* afterKeyguardGone */);
- verify(mPrimaryBouncer).showWithDismissAction(eq(action), eq(cancelAction));
- }
-
- @Test
- public void showBouncer_onlyWhenShowing() {
- mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
- mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
- verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean());
- verify(mPrimaryBouncer, never()).show(anyBoolean());
- }
-
- @Test
- public void showBouncer_notWhenBouncerAlreadyShowing() {
- mStatusBarKeyguardViewManager.hide(0 /* startTime */, 0 /* fadeoutDuration */);
- when(mPrimaryBouncer.isSecure()).thenReturn(true);
- mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
- verify(mPrimaryBouncer, never()).show(anyBoolean(), anyBoolean());
- verify(mPrimaryBouncer, never()).show(anyBoolean());
- }
-
- @Test
- public void showBouncer_showsTheBouncer() {
- mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
- verify(mPrimaryBouncer).show(anyBoolean(), eq(true));
- }
-
- @Test
- public void onPanelExpansionChanged_neverShowsDuringHintAnimation() {
- when(mNotificationPanelView.isUnlockHintRunning()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
- }
-
- @Test
- public void onPanelExpansionChanged_propagatesToBouncerOnlyIfShowing() {
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer, never()).setExpansion(eq(0.5f));
-
- when(mPrimaryBouncer.isShowing()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(
- expansionEvent(/* fraction= */ 0.6f, /* expanded= */ false, /* tracking= */ true));
- verify(mPrimaryBouncer).setExpansion(eq(0.6f));
- }
-
- @Test
- public void onPanelExpansionChanged_duplicateEventsAreIgnored() {
- when(mPrimaryBouncer.isShowing()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer).setExpansion(eq(0.5f));
-
- reset(mPrimaryBouncer);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer, never()).setExpansion(eq(0.5f));
- }
-
- @Test
- public void onPanelExpansionChanged_hideBouncer_afterKeyguardHidden() {
- mStatusBarKeyguardViewManager.hide(0, 0);
- when(mPrimaryBouncer.inTransit()).thenReturn(true);
-
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer).setExpansion(eq(EXPANSION_HIDDEN));
- }
-
- @Test
- public void onPanelExpansionChanged_showsBouncerWhenSwiping() {
- mKeyguardStateController.setCanDismissLockScreen(false);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer).show(eq(false), eq(false));
-
- // But not when it's already visible
- reset(mPrimaryBouncer);
- when(mPrimaryBouncer.isShowing()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer, never()).show(eq(false), eq(false));
-
- // Or animating away
- reset(mPrimaryBouncer);
- when(mPrimaryBouncer.isAnimatingAway()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
- verify(mPrimaryBouncer, never()).show(eq(false), eq(false));
- }
-
- @Test
- public void onPanelExpansionChanged_neverTranslatesBouncerWhenWakeAndUnlock() {
- when(mBiometricUnlockController.getMode())
- .thenReturn(BiometricUnlockController.MODE_WAKE_AND_UNLOCK);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(
- expansionEvent(
- /* fraction= */ EXPANSION_VISIBLE,
- /* expanded= */ true,
- /* tracking= */ false));
- verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
- }
-
- @Test
- public void onPanelExpansionChanged_neverTranslatesBouncerWhenDismissBouncer() {
- // Since KeyguardBouncer.EXPANSION_VISIBLE = 0 panel expansion, if the unlock is dismissing
- // the bouncer, there may be an onPanelExpansionChanged(0) call to collapse the panel
- // which would mistakenly cause the bouncer to show briefly before its visibility
- // is set to hide. Therefore, we don't want to propagate panelExpansionChanged to the
- // bouncer if the bouncer is dismissing as a result of a biometric unlock.
- when(mBiometricUnlockController.getMode())
- .thenReturn(BiometricUnlockController.MODE_DISMISS_BOUNCER);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(
- expansionEvent(
- /* fraction= */ EXPANSION_VISIBLE,
- /* expanded= */ true,
- /* tracking= */ false));
- verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
- }
-
- @Test
- public void onPanelExpansionChanged_neverTranslatesBouncerWhenOccluded() {
- when(mKeyguardStateController.isOccluded()).thenReturn(true);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(
- expansionEvent(
- /* fraction= */ EXPANSION_VISIBLE,
- /* expanded= */ true,
- /* tracking= */ false));
- verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
- }
-
- @Test
- public void onPanelExpansionChanged_neverTranslatesBouncerWhenShowBouncer() {
- // Since KeyguardBouncer.EXPANSION_VISIBLE = 0 panel expansion, if the unlock is dismissing
- // the bouncer, there may be an onPanelExpansionChanged(0) call to collapse the panel
- // which would mistakenly cause the bouncer to show briefly before its visibility
- // is set to hide. Therefore, we don't want to propagate panelExpansionChanged to the
- // bouncer if the bouncer is dismissing as a result of a biometric unlock.
- when(mBiometricUnlockController.getMode())
- .thenReturn(BiometricUnlockController.MODE_SHOW_BOUNCER);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(
- expansionEvent(
- /* fraction= */ EXPANSION_VISIBLE,
- /* expanded= */ true,
- /* tracking= */ false));
- verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
- }
-
- @Test
- public void onPanelExpansionChanged_neverTranslatesBouncerWhenShadeLocked() {
- when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
- mStatusBarKeyguardViewManager.onPanelExpansionChanged(
- expansionEvent(
- /* fraction= */ EXPANSION_VISIBLE,
- /* expanded= */ true,
- /* tracking= */ false));
- verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
- }
-
- @Test
- public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() {
- mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
- verify(mCentralSurfaces).animateKeyguardUnoccluding();
-
- when(mPrimaryBouncer.isShowing()).thenReturn(true);
- clearInvocations(mCentralSurfaces);
- mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
- verify(mCentralSurfaces, never()).animateKeyguardUnoccluding();
- }
-
- @Test
- public void setOccluded_onKeyguardOccludedChangedCalled() {
- clearInvocations(mKeyguardStateController);
- clearInvocations(mKeyguardUpdateMonitor);
-
- mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */);
- verify(mKeyguardStateController).notifyKeyguardState(true, false);
-
- clearInvocations(mKeyguardUpdateMonitor);
- clearInvocations(mKeyguardStateController);
-
- mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
- verify(mKeyguardStateController).notifyKeyguardState(true, true);
-
- clearInvocations(mKeyguardUpdateMonitor);
- clearInvocations(mKeyguardStateController);
-
- mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, false /* animated */);
- verify(mKeyguardStateController).notifyKeyguardState(true, false);
- }
-
- @Test
- public void setOccluded_isInLaunchTransition_onKeyguardOccludedChangedCalled() {
- mStatusBarKeyguardViewManager.show(null);
-
- mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
- verify(mKeyguardStateController).notifyKeyguardState(true, true);
- }
-
- @Test
- public void setOccluded_isLaunchingActivityOverLockscreen_onKeyguardOccludedChangedCalled() {
- when(mCentralSurfaces.isLaunchingActivityOverLockscreen()).thenReturn(true);
- mStatusBarKeyguardViewManager.show(null);
-
- mStatusBarKeyguardViewManager.setOccluded(true /* occluded */, false /* animated */);
- verify(mKeyguardStateController).notifyKeyguardState(true, true);
- }
-
- @Test
- public void testHiding_cancelsGoneRunnable() {
- OnDismissAction action = mock(OnDismissAction.class);
- Runnable cancelAction = mock(Runnable.class);
- mStatusBarKeyguardViewManager.dismissWithAction(
- action, cancelAction, true /* afterKeyguardGone */);
-
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- mStatusBarKeyguardViewManager.hideBouncer(true);
- mStatusBarKeyguardViewManager.hide(0, 30);
- verify(action, never()).onDismiss();
- verify(cancelAction).run();
- }
-
- @Test
- public void testHidingBouncer_cancelsGoneRunnable() {
- OnDismissAction action = mock(OnDismissAction.class);
- Runnable cancelAction = mock(Runnable.class);
- mStatusBarKeyguardViewManager.dismissWithAction(
- action, cancelAction, true /* afterKeyguardGone */);
-
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- mStatusBarKeyguardViewManager.hideBouncer(true);
-
- verify(action, never()).onDismiss();
- verify(cancelAction).run();
- }
-
- @Test
- public void testHiding_doesntCancelWhenShowing() {
- OnDismissAction action = mock(OnDismissAction.class);
- Runnable cancelAction = mock(Runnable.class);
- mStatusBarKeyguardViewManager.dismissWithAction(
- action, cancelAction, true /* afterKeyguardGone */);
-
- mStatusBarKeyguardViewManager.hide(0, 30);
- verify(action).onDismiss();
- verify(cancelAction, never()).run();
- }
-
- @Test
- public void testBouncerIsOrWillBeShowing_whenBouncerIsInTransit() {
- when(mPrimaryBouncer.isShowing()).thenReturn(false);
- when(mPrimaryBouncer.inTransit()).thenReturn(true);
-
- assertTrue(
- "Is or will be showing should be true when bouncer is in transit",
- mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing());
- }
-
- @Test
- public void testUpdateResources_delegatesToBouncer() {
- mStatusBarKeyguardViewManager.updateResources();
-
- verify(mPrimaryBouncer).updateResources();
- }
-
- @Test
- public void updateKeyguardPosition_delegatesToBouncer() {
- mStatusBarKeyguardViewManager.updateKeyguardPosition(1.0f);
-
- verify(mPrimaryBouncer).updateKeyguardPosition(1.0f);
- }
-
- @Test
- public void testIsBouncerInTransit() {
- when(mPrimaryBouncer.inTransit()).thenReturn(true);
- Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isTrue();
- when(mPrimaryBouncer.inTransit()).thenReturn(false);
- Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isFalse();
- mPrimaryBouncer = null;
- Truth.assertThat(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).isFalse();
- }
-
- private static ShadeExpansionChangeEvent expansionEvent(
- float fraction, boolean expanded, boolean tracking) {
- return new ShadeExpansionChangeEvent(
- fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
- }
-
- @Test
- public void testPredictiveBackCallback_registration() {
- /* verify that a predictive back callback is registered when the bouncer becomes visible */
- mBouncerExpansionCallback.onVisibilityChanged(true);
- verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
- mOnBackInvokedCallback.capture());
-
- /* verify that the same callback is unregistered when the bouncer becomes invisible */
- mBouncerExpansionCallback.onVisibilityChanged(false);
- verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
- eq(mOnBackInvokedCallback.getValue()));
- }
-
- @Test
- public void testPredictiveBackCallback_invocationHidesBouncer() {
- mBouncerExpansionCallback.onVisibilityChanged(true);
- /* capture the predictive back callback during registration */
- verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
- eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
- mOnBackInvokedCallback.capture());
-
- when(mPrimaryBouncer.isShowing()).thenReturn(true);
- when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
- /* invoke the back callback directly */
- mOnBackInvokedCallback.getValue().onBackInvoked();
-
- /* verify that the bouncer will be hidden as a result of the invocation */
- verify(mCentralSurfaces).setBouncerShowing(eq(false));
- }
-
- @Test
- public void testReportBouncerOnDreamWhenVisible() {
- mBouncerExpansionCallback.onVisibilityChanged(true);
- verify(mCentralSurfaces).setBouncerShowingOverDream(false);
- Mockito.clearInvocations(mCentralSurfaces);
- when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
- mBouncerExpansionCallback.onVisibilityChanged(true);
- verify(mCentralSurfaces).setBouncerShowingOverDream(true);
- }
-
- @Test
- public void testReportBouncerOnDreamWhenNotVisible() {
- mBouncerExpansionCallback.onVisibilityChanged(false);
- verify(mCentralSurfaces).setBouncerShowingOverDream(false);
- Mockito.clearInvocations(mCentralSurfaces);
- when(mDreamOverlayStateController.isOverlayActive()).thenReturn(true);
- mBouncerExpansionCallback.onVisibilityChanged(false);
- verify(mCentralSurfaces).setBouncerShowingOverDream(false);
- }
-
- @Test
- public void flag_off_DoesNotCallBouncerInteractor() {
- when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(false);
- mStatusBarKeyguardViewManager.hideBouncer(false);
- verify(mPrimaryBouncerInteractor, never()).hide();
- }
-
- @Test
- public void hideAlternateBouncer_beforeCentralSurfacesRegistered() {
- mStatusBarKeyguardViewManager =
- new StatusBarKeyguardViewManager(
- getContext(),
- mViewMediatorCallback,
- mLockPatternUtils,
- mStatusBarStateController,
- mock(ConfigurationController.class),
- mKeyguardUpdateMonitor,
- mDreamOverlayStateController,
- mock(NavigationModeController.class),
- mock(DockManager.class),
- mock(NotificationShadeWindowController.class),
- mKeyguardStateController,
- mock(NotificationMediaManager.class),
- mKeyguardBouncerFactory,
- mKeyguardMessageAreaFactory,
- Optional.of(mSysUiUnfoldComponent),
- () -> mShadeController,
- mLatencyTracker,
- mKeyguardSecurityModel,
- mFeatureFlags,
- mPrimaryBouncerCallbackInteractor,
- mPrimaryBouncerInteractor,
- mBouncerView,
- mAlternateBouncerInteractor) {
- @Override
- public ViewRootImpl getViewRootImpl() {
- return mViewRootImpl;
- }
- };
-
- // the following call before registering centralSurfaces should NOT throw a NPE:
- mStatusBarKeyguardViewManager.hideAlternateBouncer(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 eef43bd..8841521 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
@@ -40,6 +40,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.shade.NotificationShadeWindowView;
import com.android.systemui.shade.ShadeController;
@@ -92,7 +93,7 @@
mMetricsLogger = new FakeMetricsLogger();
LockscreenGestureLogger lockscreenGestureLogger = new LockscreenGestureLogger(
mMetricsLogger);
- mCommandQueue = new CommandQueue(mContext);
+ mCommandQueue = new CommandQueue(mContext, new FakeDisplayTracker(mContext));
mDependency.injectTestDependency(StatusBarStateController.class,
mock(SysuiStatusBarStateController.class));
mDependency.injectTestDependency(ShadeController.class, mShadeController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 613238f..929099a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -32,6 +32,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
@@ -78,7 +79,8 @@
mRemoteInputCallback = spy(new StatusBarRemoteInputCallback(mContext,
mock(GroupExpansionManager.class), mNotificationLockscreenUserManager,
mKeyguardStateController, mStatusBarStateController, mStatusBarKeyguardViewManager,
- mActivityStarter, mShadeController, new CommandQueue(mContext),
+ mActivityStarter, mShadeController,
+ new CommandQueue(mContext, new FakeDisplayTracker(mContext)),
mock(ActionClickLogger.class), mFakeExecutor));
mRemoteInputCallback.mChallengeReceiver = mRemoteInputCallback.new ChallengeReceiver();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index ae390a0..db8172a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -22,6 +22,7 @@
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.os.ParcelUuid
import android.provider.Settings
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
@@ -50,6 +51,7 @@
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -104,6 +106,17 @@
mock<TableLogBuffer>()
}
+ // For convenience, set up the subscription info callbacks
+ whenever(subscriptionManager.getActiveSubscriptionInfo(anyInt())).thenAnswer { invocation ->
+ when (invocation.getArgument(0) as Int) {
+ 1 -> SUB_1
+ 2 -> SUB_2
+ 3 -> SUB_3
+ 4 -> SUB_4
+ else -> null
+ }
+ }
+
wifiRepository = FakeWifiRepository()
connectionFactory =
@@ -686,6 +699,38 @@
job.cancel()
}
+ @Test
+ fun `active data change - in same group - emits unit`() =
+ runBlocking(IMMEDIATE) {
+ var latest: Unit? = null
+ val job = underTest.activeSubChangedInGroupEvent.onEach { latest = it }.launchIn(this)
+
+ getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+ .onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
+ getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+ .onActiveDataSubscriptionIdChanged(SUB_4_ID_GROUPED)
+
+ assertThat(latest).isEqualTo(Unit)
+
+ job.cancel()
+ }
+
+ @Test
+ fun `active data change - not in same group - does not emit`() =
+ runBlocking(IMMEDIATE) {
+ var latest: Unit? = null
+ val job = underTest.activeSubChangedInGroupEvent.onEach { latest = it }.launchIn(this)
+
+ getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+ .onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
+ getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>()
+ .onActiveDataSubscriptionIdChanged(SUB_1_ID)
+
+ assertThat(latest).isEqualTo(null)
+
+ job.cancel()
+ }
+
private fun createCapabilities(connected: Boolean, validated: Boolean): NetworkCapabilities =
mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(connected)
@@ -719,19 +764,50 @@
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
+
+ // Subscription 1
private const val SUB_1_ID = 1
private val SUB_1 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+ whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID()))
+ }
private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+ // Subscription 2
private const val SUB_2_ID = 2
private val SUB_2 =
- mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+ whenever(it.groupUuid).thenReturn(ParcelUuid(UUID.randomUUID()))
+ }
private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+ // Subs 3 and 4 are considered to be in the same group ------------------------------------
+ private val GROUP_ID_3_4 = ParcelUuid(UUID.randomUUID())
+
+ // Subscription 3
+ private const val SUB_3_ID_GROUPED = 3
+ private val SUB_3 =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_3_ID_GROUPED)
+ whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+ }
+
+ // Subscription 4
+ private const val SUB_4_ID_GROUPED = 4
+ private val SUB_4 =
+ mock<SubscriptionInfo>().also {
+ whenever(it.subscriptionId).thenReturn(SUB_4_ID_GROUPED)
+ whenever(it.groupUuid).thenReturn(GROUP_ID_3_4)
+ }
+
+ // Subs 3 and 4 are considered to be in the same group ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
private const val NET_ID = 123
private val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
+ // Carrier merged subscription
private const val SUB_CM_ID = 5
private val SUB_CM =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
index b32058f..3dccbbf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
@@ -45,7 +45,7 @@
@Test
fun testLogNetworkCapsChange_bufferHasInfo() {
- logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS)
+ logger.logOnCapabilitiesChanged(NET_1, NET_1_CAPS, isDefaultNetworkCallback = true)
val stringWriter = StringWriter()
buffer.dump(PrintWriter(stringWriter), tailLength = 0)
@@ -54,6 +54,7 @@
val expectedNetId = NET_1_ID.toString()
val expectedCaps = NET_1_CAPS.toString()
+ assertThat(actualString).contains("true")
assertThat(actualString).contains(expectedNetId)
assertThat(actualString).contains(expectedCaps)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
index 87ce8fa..7099f1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt
@@ -21,7 +21,10 @@
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.TransportInfo
+import android.net.VpnTransportInfo
import android.net.vcn.VcnTransportInfo
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
@@ -243,6 +246,54 @@
job.cancel()
}
+ /** Regression test for b/266628069. */
+ @Test
+ fun isWifiDefault_transportInfoIsNotWifi_andNoWifiTransport_false() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.isWifiDefault.launchIn(this)
+
+ val transportInfo = VpnTransportInfo(
+ /* type= */ 0,
+ /* sessionId= */ "sessionId",
+ )
+ val networkCapabilities = mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
+ whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(false)
+ whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+ whenever(it.transportInfo).thenReturn(transportInfo)
+ }
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
+
+ assertThat(underTest.isWifiDefault.value).isFalse()
+
+ job.cancel()
+ }
+
+ /** Regression test for b/266628069. */
+ @Test
+ fun isWifiDefault_transportInfoIsNotWifi_butHasWifiTransport_true() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.isWifiDefault.launchIn(this)
+
+ val transportInfo = VpnTransportInfo(
+ /* type= */ 0,
+ /* sessionId= */ "sessionId",
+ )
+ val networkCapabilities = mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_VPN)).thenReturn(true)
+ whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(false)
+ whenever(it.transportInfo).thenReturn(transportInfo)
+ }
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, networkCapabilities)
+
+ assertThat(underTest.isWifiDefault.value).isTrue()
+
+ job.cancel()
+ }
+
@Test
fun isWifiDefault_cellularVcnNetwork_isTrue() = runBlocking(IMMEDIATE) {
val job = underTest.isWifiDefault.launchIn(this)
@@ -260,6 +311,24 @@
}
@Test
+ fun wifiNetwork_cellularAndWifiTransports_usesCellular_isTrue() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.isWifiDefault.launchIn(this)
+
+ val capabilities = mock<NetworkCapabilities>().apply {
+ whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
+ }
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+ assertThat(underTest.isWifiDefault.value).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
fun isWifiDefault_cellularNotVcnNetwork_isFalse() = runBlocking(IMMEDIATE) {
val job = underTest.isWifiDefault.launchIn(this)
@@ -467,6 +536,28 @@
job.cancel()
}
+ /** Regression test for b/266628069. */
+ @Test
+ fun wifiNetwork_transportInfoIsNotWifi_flowHasNoNetwork() =
+ runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val transportInfo = VpnTransportInfo(
+ /* type= */ 0,
+ /* sessionId= */ "sessionId",
+ )
+ getNetworkCallback()
+ .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(transportInfo))
+
+ assertThat(latest is WifiNetworkModel.Inactive).isTrue()
+
+ job.cancel()
+ }
+
@Test
fun wifiNetwork_cellularVcnNetworkAdded_flowHasNetwork() = runBlocking(IMMEDIATE) {
var latest: WifiNetworkModel? = null
@@ -535,6 +626,31 @@
}
@Test
+ fun wifiNetwork_cellularAndWifiTransports_usesCellular() =
+ runBlocking(IMMEDIATE) {
+ var latest: WifiNetworkModel? = null
+ val job = underTest
+ .wifiNetwork
+ .onEach { latest = it }
+ .launchIn(this)
+
+ val capabilities = mock<NetworkCapabilities>().apply {
+ whenever(this.hasTransport(TRANSPORT_CELLULAR)).thenReturn(true)
+ whenever(this.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
+ whenever(this.transportInfo).thenReturn(VcnTransportInfo(PRIMARY_WIFI_INFO))
+ }
+
+ getNetworkCallback().onCapabilitiesChanged(NETWORK, capabilities)
+
+ assertThat(latest is WifiNetworkModel.Active).isTrue()
+ val latestActive = latest as WifiNetworkModel.Active
+ assertThat(latestActive.networkId).isEqualTo(NETWORK_ID)
+ assertThat(latestActive.ssid).isEqualTo(SSID)
+
+ job.cancel()
+ }
+
+ @Test
fun wifiNetwork_newPrimaryWifiNetwork_flowHasNewNetwork() = runBlocking(IMMEDIATE) {
var latest: WifiNetworkModel? = null
val job = underTest
@@ -870,12 +986,12 @@
}
private fun createWifiNetworkCapabilities(
- wifiInfo: WifiInfo,
+ transportInfo: TransportInfo,
isValidated: Boolean = true,
): NetworkCapabilities {
return mock<NetworkCapabilities>().also {
whenever(it.hasTransport(TRANSPORT_WIFI)).thenReturn(true)
- whenever(it.transportInfo).thenReturn(wifiInfo)
+ whenever(it.transportInfo).thenReturn(transportInfo)
whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(isValidated)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index 45f7df3..c7c6b94 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -1172,7 +1172,7 @@
inner class Listener : TemporaryViewDisplayController.Listener {
val permanentlyRemovedIds = mutableListOf<String>()
- override fun onInfoPermanentlyRemoved(id: String) {
+ override fun onInfoPermanentlyRemoved(id: String, reason: String) {
permanentlyRemovedIds.add(id)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
index 45eb1f9..dd04ac4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinatorTest.kt
@@ -66,7 +66,7 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class ChipbarCoordinatorTest : SysuiTestCase() {
- private lateinit var underTest: FakeChipbarCoordinator
+ private lateinit var underTest: ChipbarCoordinator
@Mock private lateinit var logger: ChipbarLogger
@Mock private lateinit var accessibilityManager: AccessibilityManager
@@ -100,7 +100,7 @@
uiEventLoggerFake = UiEventLoggerFake()
underTest =
- FakeChipbarCoordinator(
+ ChipbarCoordinator(
context,
logger,
windowManager,
@@ -436,6 +436,23 @@
verify(logger).logViewUpdate(eq(WINDOW_TITLE), eq("new title text"), any())
}
+ /** Regression test for b/266209420. */
+ @Test
+ fun displayViewThenImmediateRemoval_viewStillRemoved() {
+ underTest.displayView(
+ createChipbarInfo(
+ Icon.Resource(R.drawable.ic_cake, contentDescription = null),
+ Text.Loaded("title text"),
+ endItem = ChipbarEndItem.Error,
+ ),
+ )
+ val chipbarView = getChipbarView()
+
+ underTest.removeView(DEVICE_ID, "test reason")
+
+ verify(windowManager).removeView(chipbarView)
+ }
+
@Test
fun swipeToDismiss_false_neverListensForGesture() {
underTest.displayView(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
deleted file mode 100644
index ffac8f6..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/FakeChipbarCoordinator.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.temporarydisplay.chipbar
-
-import android.content.Context
-import android.os.PowerManager
-import android.view.ViewGroup
-import android.view.WindowManager
-import android.view.accessibility.AccessibilityManager
-import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.statusbar.VibratorHelper
-import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.time.SystemClock
-import com.android.systemui.util.view.ViewUtil
-import com.android.systemui.util.wakelock.WakeLock
-
-/** A fake implementation of [ChipbarCoordinator] for testing. */
-class FakeChipbarCoordinator(
- context: Context,
- logger: ChipbarLogger,
- windowManager: WindowManager,
- mainExecutor: DelayableExecutor,
- accessibilityManager: AccessibilityManager,
- configurationController: ConfigurationController,
- dumpManager: DumpManager,
- powerManager: PowerManager,
- falsingManager: FalsingManager,
- falsingCollector: FalsingCollector,
- swipeChipbarAwayGestureHandler: SwipeChipbarAwayGestureHandler,
- viewUtil: ViewUtil,
- vibratorHelper: VibratorHelper,
- wakeLockBuilder: WakeLock.Builder,
- systemClock: SystemClock,
-) :
- ChipbarCoordinator(
- context,
- logger,
- windowManager,
- mainExecutor,
- accessibilityManager,
- configurationController,
- dumpManager,
- powerManager,
- falsingManager,
- falsingCollector,
- swipeChipbarAwayGestureHandler,
- viewUtil,
- vibratorHelper,
- wakeLockBuilder,
- systemClock,
- ) {
- override fun animateViewOut(view: ViewGroup, removalReason: String?, onAnimationEnd: Runnable) {
- // Just bypass the animation in tests
- onAnimationEnd.run()
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt
index a87a950..c539246 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/chipbar/SwipeChipbarAwayGestureHandlerTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer
import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -36,7 +37,7 @@
@Before
fun setUp() {
- underTest = SwipeChipbarAwayGestureHandler(context, mock())
+ underTest = SwipeChipbarAwayGestureHandler(context, FakeDisplayTracker(mContext), mock())
}
@Test
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 68ccc30..bc33439 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -91,6 +91,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
import com.android.systemui.shade.NotificationShadeWindowView;
@@ -287,6 +288,8 @@
private TestableLooper mTestableLooper;
+ private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -333,7 +336,7 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- mSysUiState = new SysUiState();
+ mSysUiState = new SysUiState(mDisplayTracker);
mSysUiState.addCallback(sysUiFlags -> {
mSysUiStateBubblesManageMenuExpanded =
(sysUiFlags
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 7ae47b4..45489d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -29,6 +29,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.model.SysUiState;
import com.android.systemui.notetask.NoteTaskInitializer;
+import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -63,6 +64,7 @@
@RunWith(AndroidJUnit4.class)
public class WMShellTest extends SysuiTestCase {
WMShell mWMShell;
+ FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
@Mock ShellInterface mShellInterface;
@Mock CommandQueue mCommandQueue;
@@ -100,6 +102,7 @@
mProtoTracer,
mWakefulnessLifecycle,
mUserTracker,
+ mDisplayTracker,
mNoteTaskInitializer,
mSysUiMainExecutor
);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
new file mode 100644
index 0000000..5641832
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository {
+ private val _isLockedOut = MutableStateFlow<Boolean>(false)
+ override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow()
+
+ fun setLockedOut(lockedOut: Boolean) {
+ _isLockedOut.value = lockedOut
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 15b4736..065fe89 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -29,6 +29,7 @@
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
/** Fake implementation of [KeyguardRepository] */
class FakeKeyguardRepository : KeyguardRepository {
@@ -101,6 +102,13 @@
private val _biometricUnlockSource = MutableStateFlow<BiometricUnlockSource?>(null)
override val biometricUnlockSource: Flow<BiometricUnlockSource?> = _biometricUnlockSource
+ private val _isQuickSettingsVisible = MutableStateFlow(false)
+ override val isQuickSettingsVisible: Flow<Boolean> = _isQuickSettingsVisible.asStateFlow()
+
+ override fun setQuickSettingsVisible(isVisible: Boolean) {
+ _isQuickSettingsVisible.value = isVisible
+ }
+
override fun isKeyguardShowing(): Boolean {
return _isKeyguardShowing.value
}
@@ -169,6 +177,10 @@
_dozeTransitionModel.value = model
}
+ fun setStatusBarState(state: StatusBarState) {
+ _statusBarState.value = state
+ }
+
override fun isUdfpsSupported(): Boolean {
return _isUdfpsSupported.value
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 6c44244..eac1bd1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -22,13 +22,15 @@
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import java.util.UUID
+import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
/** Fake implementation of [KeyguardTransitionRepository] */
class FakeKeyguardTransitionRepository : KeyguardTransitionRepository {
- private val _transitions = MutableSharedFlow<TransitionStep>()
+ private val _transitions =
+ MutableSharedFlow<TransitionStep>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
override val transitions: SharedFlow<TransitionStep> = _transitions
suspend fun sendTransitionStep(step: TransitionStep) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt
new file mode 100644
index 0000000..6ae7c34
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeDisplayTracker.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.settings
+
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.view.Display
+import java.util.concurrent.Executor
+
+class FakeDisplayTracker internal constructor(val context: Context) : DisplayTracker {
+ val displayManager: DisplayManager = context.getSystemService(DisplayManager::class.java)!!
+ override var defaultDisplayId: Int = Display.DEFAULT_DISPLAY
+ override var allDisplays: Array<Display> = displayManager.displays
+
+ private val displayCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
+ private val brightnessCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
+ override fun addDisplayChangeCallback(callback: DisplayTracker.Callback, executor: Executor) {
+ displayCallbacks.add(callback)
+ }
+ override fun addBrightnessChangeCallback(
+ callback: DisplayTracker.Callback,
+ executor: Executor
+ ) {
+ brightnessCallbacks.add(callback)
+ }
+
+ override fun removeCallback(callback: DisplayTracker.Callback) {
+ displayCallbacks.remove(callback)
+ brightnessCallbacks.remove(callback)
+ }
+
+ fun setDefaultDisplay(displayId: Int) {
+ defaultDisplayId = displayId
+ }
+
+ fun setDisplays(displays: Array<Display>) {
+ allDisplays = displays
+ }
+
+ fun triggerOnDisplayAdded(displayId: Int) {
+ notifyCallbacks({ onDisplayAdded(displayId) }, displayCallbacks)
+ }
+
+ fun triggerOnDisplayRemoved(displayId: Int) {
+ notifyCallbacks({ onDisplayRemoved(displayId) }, displayCallbacks)
+ }
+
+ fun triggerOnDisplayChanged(displayId: Int) {
+ notifyCallbacks({ onDisplayChanged(displayId) }, displayCallbacks)
+ }
+
+ fun triggerOnDisplayBrightnessChanged(displayId: Int) {
+ notifyCallbacks({ onDisplayChanged(displayId) }, brightnessCallbacks)
+ }
+
+ private inline fun notifyCallbacks(
+ crossinline action: DisplayTracker.Callback.() -> Unit,
+ list: List<DisplayTracker.Callback>
+ ) {
+ list.forEach { it.action() }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index 0dd1fc7..251014f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -67,7 +67,10 @@
_userHandle = UserHandle.of(_userId)
val copy = callbacks.toList()
- copy.forEach { it.onUserChanged(_userId, userContext) }
+ copy.forEach {
+ it.onUserChanging(_userId, userContext)
+ it.onUserChanged(_userId, userContext)
+ }
}
fun onProfileChanged() {
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 3584f16..ac78228 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -51,6 +51,7 @@
import android.app.GameModeInfo;
import android.app.GameState;
import android.app.IGameManagerService;
+import android.app.IUidObserver;
import android.app.compat.PackageOverride;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -118,6 +119,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Service to manage game related features.
@@ -171,40 +173,19 @@
private final ArrayMap<String, GamePackageConfiguration> mOverrideConfigs = new ArrayMap<>();
@Nullable
private final GameServiceController mGameServiceController;
+ private final Object mUidObserverLock = new Object();
+ @VisibleForTesting
+ @Nullable
+ final UidObserver mUidObserver;
+ @GuardedBy("mUidObserverLock")
+ private final Set<Integer> mForegroundGameUids = new HashSet<>();
public GameManagerService(Context context) {
this(context, createServiceThread().getLooper());
}
GameManagerService(Context context, Looper looper) {
- mContext = context;
- mHandler = new SettingsHandler(looper);
- mPackageManager = mContext.getPackageManager();
- mUserManager = mContext.getSystemService(UserManager.class);
- mPlatformCompat = IPlatformCompat.Stub.asInterface(
- ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
- mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
- mSystemDir = new File(Environment.getDataDirectory(), "system");
- mSystemDir.mkdirs();
- FileUtils.setPermissions(mSystemDir.toString(),
- FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
- -1, -1);
- mGameModeInterventionListFile = new AtomicFile(new File(mSystemDir,
- GAME_MODE_INTERVENTION_LIST_FILE_NAME));
- FileUtils.setPermissions(mGameModeInterventionListFile.getBaseFile().getAbsolutePath(),
- FileUtils.S_IRUSR | FileUtils.S_IWUSR
- | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
- -1, -1);
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_GAME_SERVICE)) {
- mGameServiceController = new GameServiceController(
- context, BackgroundThread.getExecutor(),
- new GameServiceProviderSelectorImpl(
- context.getResources(),
- context.getPackageManager()),
- new GameServiceProviderInstanceFactoryImpl(context));
- } else {
- mGameServiceController = null;
- }
+ this(context, looper, Environment.getDataDirectory());
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
@@ -237,6 +218,14 @@
} else {
mGameServiceController = null;
}
+ mUidObserver = new UidObserver();
+ try {
+ ActivityManager.getService().registerUidObserver(mUidObserver,
+ ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not register UidObserver");
+ }
}
@Override
@@ -1874,4 +1863,66 @@
* load dynamic library for frame rate overriding JNI calls
*/
private static native void nativeSetOverrideFrameRate(int uid, float frameRate);
+
+ final class UidObserver extends IUidObserver.Stub {
+ @Override
+ public void onUidIdle(int uid, boolean disabled) {}
+
+ @Override
+ public void onUidGone(int uid, boolean disabled) {
+ synchronized (mUidObserverLock) {
+ disableGameMode(uid);
+ }
+ }
+
+ @Override
+ public void onUidActive(int uid) {}
+
+ @Override
+ public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) {
+ synchronized (mUidObserverLock) {
+ if (ActivityManager.isProcStateBackground(procState)) {
+ disableGameMode(uid);
+ return;
+ }
+
+ final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+ if (packages == null || packages.length == 0) {
+ return;
+ }
+
+ final int userId = mContext.getUserId();
+ if (!Arrays.stream(packages).anyMatch(p -> isPackageGame(p, userId))) {
+ return;
+ }
+
+ if (mForegroundGameUids.isEmpty()) {
+ Slog.v(TAG, "Game power mode ON (process state was changed to foreground)");
+ mPowerManagerInternal.setPowerMode(Mode.GAME, true);
+ }
+ mForegroundGameUids.add(uid);
+ }
+ }
+
+ private void disableGameMode(int uid) {
+ synchronized (mUidObserverLock) {
+ if (!mForegroundGameUids.contains(uid)) {
+ return;
+ }
+ mForegroundGameUids.remove(uid);
+ if (!mForegroundGameUids.isEmpty()) {
+ return;
+ }
+ Slog.v(TAG,
+ "Game power mode OFF (process remomved or state changed to background)");
+ mPowerManagerInternal.setPowerMode(Mode.GAME, false);
+ }
+ }
+
+ @Override
+ public void onUidCachedChanged(int uid, boolean cached) {}
+
+ @Override
+ public void onUidProcAdjChanged(int uid) {}
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 278c98f..0589cfc 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -56,6 +56,7 @@
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
@@ -434,6 +435,48 @@
return device;
}
+ private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+ AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
+ AudioDeviceInfo.TYPE_WIRED_HEADSET,
+ AudioDeviceInfo.TYPE_USB_HEADSET,
+ AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+ AudioDeviceInfo.TYPE_HEARING_AID,
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ AudioDeviceInfo.TYPE_USB_DEVICE,
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ AudioDeviceInfo.TYPE_LINE_ANALOG,
+ AudioDeviceInfo.TYPE_HDMI,
+ AudioDeviceInfo.TYPE_AUX_LINE
+ };
+
+ /*package */ static boolean isValidCommunicationDevice(AudioDeviceInfo device) {
+ for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
+ if (device.getType() == type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
+ ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
+ AudioDeviceInfo[] allDevices =
+ AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
+ for (AudioDeviceInfo device : allDevices) {
+ if (isValidCommunicationDevice(device)) {
+ commDevices.add(device);
+ }
+ }
+ return commDevices;
+ }
+
+ private @Nullable AudioDeviceInfo getCommunicationDeviceOfType(int type) {
+ return getAvailableCommunicationDevices().stream().filter(d -> d.getType() == type)
+ .findFirst().orElse(null);
+ }
+
/**
* Returns the device currently requested for communication use case.
* @return AudioDeviceInfo the requested device for communication.
@@ -441,7 +484,29 @@
/* package */ AudioDeviceInfo getCommunicationDevice() {
synchronized (mDeviceStateLock) {
updateActiveCommunicationDevice();
- return mActiveCommunicationDevice;
+ AudioDeviceInfo device = mActiveCommunicationDevice;
+ // make sure we return a valid communication device (i.e. a device that is allowed by
+ // setCommunicationDevice()) for consistency.
+ if (device != null) {
+ // a digital dock is used instead of the speaker in speakerphone mode and should
+ // be reflected as such
+ if (device.getType() == AudioDeviceInfo.TYPE_DOCK) {
+ device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
+ }
+ }
+ // Try to default to earpiece when current communication device is not valid. This can
+ // happen for instance if no call is active. If no earpiece device is available take the
+ // first valid communication device
+ if (device == null || !AudioDeviceBroker.isValidCommunicationDevice(device)) {
+ device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE);
+ if (device == null) {
+ List<AudioDeviceInfo> commDevices = getAvailableCommunicationDevices();
+ if (!commDevices.isEmpty()) {
+ device = commDevices.get(0);
+ }
+ }
+ }
+ return device;
}
}
@@ -918,8 +983,8 @@
@GuardedBy("mDeviceStateLock")
private void dispatchCommunicationDevice() {
- int portId = (mActiveCommunicationDevice == null) ? 0
- : mActiveCommunicationDevice.getId();
+ AudioDeviceInfo device = getCommunicationDevice();
+ int portId = device != null ? device.getId() : 0;
if (portId == mCurCommunicationPortId) {
return;
}
@@ -936,6 +1001,7 @@
mCommDevDispatchers.finishBroadcast();
}
+
//---------------------------------------------------------------------
// Communication with (to) AudioService
//TODO check whether the AudioService methods are candidates to move here
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1bd8f1e..dfb2467 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1253,6 +1253,20 @@
0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */);
}
+ private void initVolumeStreamStates() {
+ int numStreamTypes = AudioSystem.getNumStreamTypes();
+ synchronized (VolumeStreamState.class) {
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ VolumeStreamState streamState = mStreamStates[streamType];
+ int groupId = getVolumeGroupForStreamType(streamType);
+ if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
+ && sVolumeGroupStates.indexOfKey(groupId) >= 0) {
+ streamState.setVolumeGroupState(sVolumeGroupStates.get(groupId));
+ }
+ }
+ }
+ }
+
/**
* Separating notification volume from ring is NOT of aliasing the corresponding streams
* @param properties
@@ -1282,6 +1296,8 @@
// mSafeUsbMediaVolumeIndex must be initialized after createStreamStates() because it
// relies on audio policy having correct ranges for volume indexes.
mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
+ // Link VGS on VSS
+ initVolumeStreamStates();
// Call setRingerModeInt() to apply correct mute
// state on streams affected by ringer mode.
@@ -3340,15 +3356,7 @@
} else {
state = direction == AudioManager.ADJUST_MUTE;
}
- for (int stream = 0; stream < mStreamStates.length; stream++) {
- if (streamTypeAlias == mStreamVolumeAlias[stream]) {
- if (!(readCameraSoundForced()
- && (mStreamStates[stream].getStreamType()
- == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
- mStreamStates[stream].mute(state);
- }
- }
- }
+ muteAliasStreams(streamTypeAlias, state);
} else if ((direction == AudioManager.ADJUST_RAISE) &&
!checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
@@ -3363,7 +3371,7 @@
// Unmute the stream if it was previously muted
if (direction == AudioManager.ADJUST_RAISE) {
// unmute immediately for volume up
- streamState.mute(false);
+ muteAliasStreams(streamTypeAlias, false);
} else if (direction == AudioManager.ADJUST_LOWER) {
if (mIsSingleVolume) {
sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
@@ -3489,6 +3497,42 @@
sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
}
+ /**
+ * Loops on aliasted stream, update the mute cache attribute of each
+ * {@see AudioService#VolumeStreamState}, and then apply the change.
+ * It prevents to unnecessary {@see AudioSystem#setStreamVolume} done for each stream
+ * and aliases before mute change changed and after.
+ */
+ private void muteAliasStreams(int streamAlias, boolean state) {
+ synchronized (VolumeStreamState.class) {
+ List<Integer> streamsToMute = new ArrayList<>();
+ for (int stream = 0; stream < mStreamStates.length; stream++) {
+ if (streamAlias == mStreamVolumeAlias[stream]) {
+ if (!(readCameraSoundForced()
+ && (mStreamStates[stream].getStreamType()
+ == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
+ boolean changed = mStreamStates[stream].mute(state, /* apply= */ false);
+ if (changed) {
+ streamsToMute.add(stream);
+ }
+ }
+ }
+ }
+ streamsToMute.forEach(streamToMute -> {
+ mStreamStates[streamToMute].doMute();
+ broadcastMuteSetting(streamToMute, state);
+ });
+ }
+ }
+
+ private void broadcastMuteSetting(int streamType, boolean isMuted) {
+ // Stream mute changed, fire the intent.
+ Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
+ intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, isMuted);
+ sendBroadcastToAll(intent);
+ }
+
// Called after a delay when volume down is pressed while muted
private void onUnmuteStream(int stream, int flags) {
boolean wasMuted;
@@ -3593,8 +3637,19 @@
return false;
}
+ /**
+ * Update stream volume, ringer mode and mute status after a volume index change
+ * @param streamType
+ * @param index
+ * @param flags
+ * @param device the device for which the volume is changed
+ * @param caller
+ * @param hasModifyAudioSettings
+ * @param canChangeMute true if the origin of this event is one where the mute state should be
+ * updated following the change in volume index
+ */
private void onSetStreamVolume(int streamType, int index, int flags, int device,
- String caller, boolean hasModifyAudioSettings) {
+ String caller, boolean hasModifyAudioSettings, boolean canChangeMute) {
final int stream = mStreamVolumeAlias[streamType];
setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings);
// setting volume on ui sounds stream type also controls silent mode
@@ -3604,11 +3659,10 @@
TAG + ".onSetStreamVolume", false /*external*/);
}
// setting non-zero volume for a muted stream unmutes the stream and vice versa
- // (only when changing volume for the current device),
// except for BT SCO stream where only explicit mute is allowed to comply to BT requirements
- if ((streamType != AudioSystem.STREAM_BLUETOOTH_SCO)
- && (getDeviceForStream(stream) == device)) {
- mStreamStates[stream].mute(index == 0);
+ if ((streamType != AudioSystem.STREAM_BLUETOOTH_SCO) && canChangeMute) {
+ // As adjustStreamVolume with muteAdjust flags mute/unmutes stream and aliased streams.
+ muteAliasStreams(stream, index == 0);
}
}
@@ -3664,29 +3718,27 @@
}
- /** @see AudioManager#setVolumeIndexForAttributes(attr, int, int) */
- public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags,
+ /** @see AudioManager#setVolumeGroupVolumeIndex(int, int, int) */
+ public void setVolumeGroupVolumeIndex(int groupId, int index, int flags,
String callingPackage, String attributionTag) {
enforceModifyAudioRoutingPermission();
- Objects.requireNonNull(attr, "attr must not be null");
- final int volumeGroup = getVolumeGroupIdForAttributes(attr);
- if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) {
- Log.e(TAG, ": no volume group found for attributes " + attr.toString());
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
return;
}
- final VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
- sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(),
- index/*val1*/, flags/*val2*/, callingPackage));
+ sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, vgs.name(),
+ index, flags, callingPackage + ", user " + getCurrentUserId()));
vgs.setVolumeIndex(index, flags);
// For legacy reason, propagate to all streams associated to this volume group
- for (final int groupedStream : vgs.getLegacyStreamTypes()) {
+ for (int groupedStream : vgs.getLegacyStreamTypes()) {
try {
ensureValidStreamType(groupedStream);
} catch (IllegalArgumentException e) {
- Log.d(TAG, "volume group " + volumeGroup + " has internal streams (" + groupedStream
+ Log.d(TAG, "volume group " + groupId + " has internal streams (" + groupedStream
+ "), do not change associated stream volume");
continue;
}
@@ -3698,7 +3750,7 @@
@Nullable
private AudioVolumeGroup getAudioVolumeGroupById(int volumeGroupId) {
- for (final AudioVolumeGroup avg : AudioVolumeGroup.getAudioVolumeGroups()) {
+ for (AudioVolumeGroup avg : AudioVolumeGroup.getAudioVolumeGroups()) {
if (avg.getId() == volumeGroupId) {
return avg;
}
@@ -3708,30 +3760,42 @@
return null;
}
- /** @see AudioManager#getVolumeIndexForAttributes(attr) */
- public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
+ /** @see AudioManager#getVolumeGroupVolumeIndex(int) */
+ public int getVolumeGroupVolumeIndex(int groupId) {
enforceModifyAudioRoutingPermission();
- Objects.requireNonNull(attr, "attr must not be null");
- final int volumeGroup = getVolumeGroupIdForAttributes(attr);
- if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) {
- throw new IllegalArgumentException("No volume group for attributes " + attr);
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ throw new IllegalArgumentException("No volume group for id " + groupId);
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ // Return 0 when muted, not min index since for e.g. Voice Call, it has a non zero
+ // min but it mutable on permission condition.
+ return vgs.isMuted() ? 0 : vgs.getVolumeIndex();
}
- final VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup);
- return vgs.getVolumeIndex();
}
- /** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */
- public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
+ /** @see AudioManager#getVolumeGroupMaxVolumeIndex(int) */
+ public int getVolumeGroupMaxVolumeIndex(int groupId) {
enforceModifyAudioRoutingPermission();
- Objects.requireNonNull(attr, "attr must not be null");
- return AudioSystem.getMaxVolumeIndexForAttributes(attr);
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ throw new IllegalArgumentException("No volume group for id " + groupId);
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.getMaxIndex();
+ }
}
- /** @see AudioManager#getMinVolumeIndexForAttributes(attr) */
- public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
+ /** @see AudioManager#getVolumeGroupMinVolumeIndex(int) */
+ public int getVolumeGroupMinVolumeIndex(int groupId) {
enforceModifyAudioRoutingPermission();
- Objects.requireNonNull(attr, "attr must not be null");
- return AudioSystem.getMinVolumeIndexForAttributes(attr);
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ throw new IllegalArgumentException("No volume group for id " + groupId);
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.getMinIndex();
+ }
}
/** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes)
@@ -3808,6 +3872,70 @@
callingPackage, /*attributionTag*/ null);
}
+ /** @see AudioManager#adjustVolumeGroupVolume(int, int, int) */
+ public void adjustVolumeGroupVolume(int groupId, int direction, int flags,
+ String callingPackage) {
+ ensureValidDirection(direction);
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
+ return;
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ // For compatibility reason, use stream API if group linked to a valid stream
+ boolean fallbackOnStream = false;
+ for (int stream : vgs.getLegacyStreamTypes()) {
+ try {
+ ensureValidStreamType(stream);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "volume group " + groupId + " has internal streams (" + stream
+ + "), do not change associated stream volume");
+ continue;
+ }
+ // Note: Group and Stream does not share same convention, 0 is mute for stream,
+ // min index is acting as mute for Groups
+ if (vgs.isVssMuteBijective(stream)) {
+ adjustStreamVolume(stream, direction, flags, callingPackage);
+ if (isMuteAdjust(direction)) {
+ // will be propagated to all aliased streams
+ return;
+ }
+ fallbackOnStream = true;
+ }
+ }
+ if (fallbackOnStream) {
+ // Handled by at least one stream, will be propagated to group, bailing out.
+ return;
+ }
+ sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_GROUP_VOL, vgs.name(),
+ direction, flags, callingPackage));
+ vgs.adjustVolume(direction, flags);
+ }
+
+ /** @see AudioManager#getLastAudibleVolumeGroupVolume(int) */
+ public int getLastAudibleVolumeGroupVolume(int groupId) {
+ enforceQueryStatePermission();
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
+ return 0;
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.getVolumeIndex();
+ }
+ }
+
+ /** @see AudioManager#isVolumeGroupMuted(int) */
+ public boolean isVolumeGroupMuted(int groupId) {
+ synchronized (VolumeStreamState.class) {
+ if (sVolumeGroupStates.indexOfKey(groupId) < 0) {
+ Log.e(TAG, ": no volume group found for id " + groupId);
+ return false;
+ }
+ VolumeGroupState vgs = sVolumeGroupStates.get(groupId);
+ return vgs.isMuted();
+ }
+ }
+
/** @see AudioManager#setStreamVolume(int, int, int)
* Part of service interface, check permissions here */
public void setStreamVolumeWithAttribution(int streamType, int index, int flags,
@@ -4247,7 +4375,10 @@
mPendingVolumeCommand = new StreamVolumeCommand(
streamType, index, flags, device);
} else {
- onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings);
+ onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings,
+ // ada is non-null when called from setDeviceVolume,
+ // which shouldn't update the mute state
+ ada == null /*canChangeMute*/);
index = mStreamStates[streamType].getIndex(device);
}
}
@@ -4264,31 +4395,6 @@
}
}
-
-
- private int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
- Objects.requireNonNull(attributes, "attributes must not be null");
- int volumeGroupId = getVolumeGroupIdForAttributesInt(attributes);
- if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
- return volumeGroupId;
- }
- // The default volume group is the one hosted by default product strategy, i.e.
- // supporting Default Attributes
- return getVolumeGroupIdForAttributesInt(AudioProductStrategy.getDefaultAttributes());
- }
-
- private int getVolumeGroupIdForAttributesInt(@NonNull AudioAttributes attributes) {
- Objects.requireNonNull(attributes, "attributes must not be null");
- for (final AudioProductStrategy productStrategy :
- AudioProductStrategy.getAudioProductStrategies()) {
- int volumeGroupId = productStrategy.getVolumeGroupIdForAudioAttributes(attributes);
- if (volumeGroupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
- return volumeGroupId;
- }
- }
- return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
- }
-
private void dispatchAbsoluteVolumeChanged(int streamType, AbsoluteVolumeDeviceInfo deviceInfo,
int index) {
VolumeInfo volumeInfo = deviceInfo.getMatchingVolumeInfoForStream(streamType);
@@ -4321,7 +4427,6 @@
}
}
-
// No ringer or zen muted stream volumes can be changed unless it'll exit dnd
private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
switch (mNm.getZenMode()) {
@@ -5013,7 +5118,7 @@
}
private void setRingerMode(int ringerMode, String caller, boolean external) {
- if (mUseFixedVolume || mIsSingleVolume) {
+ if (mUseFixedVolume || mIsSingleVolume || mUseVolumeGroupAliases) {
return;
}
if (caller == null || caller.length() == 0) {
@@ -5838,7 +5943,7 @@
}
}
- readVolumeGroupsSettings();
+ readVolumeGroupsSettings(userSwitch);
if (DEBUG_VOL) {
Log.d(TAG, "Restoring device volume behavior");
@@ -5846,46 +5951,16 @@
restoreDeviceVolumeBehavior();
}
- private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
- AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
- AudioDeviceInfo.TYPE_WIRED_HEADSET,
- AudioDeviceInfo.TYPE_USB_HEADSET,
- AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
- AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
- AudioDeviceInfo.TYPE_HEARING_AID,
- AudioDeviceInfo.TYPE_BLE_HEADSET,
- AudioDeviceInfo.TYPE_USB_DEVICE,
- AudioDeviceInfo.TYPE_BLE_SPEAKER,
- AudioDeviceInfo.TYPE_LINE_ANALOG,
- AudioDeviceInfo.TYPE_HDMI,
- AudioDeviceInfo.TYPE_AUX_LINE
- };
-
- private boolean isValidCommunicationDevice(AudioDeviceInfo device) {
- for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
- if (device.getType() == type) {
- return true;
- }
- }
- return false;
- }
-
/** @see AudioManager#getAvailableCommunicationDevices(int) */
public int[] getAvailableCommunicationDeviceIds() {
- ArrayList<Integer> deviceIds = new ArrayList<>();
- AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
- for (AudioDeviceInfo device : devices) {
- if (isValidCommunicationDevice(device)) {
- deviceIds.add(device.getId());
- }
- }
- return deviceIds.stream().mapToInt(Integer::intValue).toArray();
+ List<AudioDeviceInfo> commDevices = AudioDeviceBroker.getAvailableCommunicationDevices();
+ return commDevices.stream().mapToInt(AudioDeviceInfo::getId).toArray();
}
- /**
- * @see AudioManager#setCommunicationDevice(int)
- * @see AudioManager#clearCommunicationDevice()
- */
+
+ /**
+ * @see AudioManager#setCommunicationDevice(int)
+ * @see AudioManager#clearCommunicationDevice()
+ */
public boolean setCommunicationDevice(IBinder cb, int portId) {
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
@@ -5894,9 +5969,10 @@
if (portId != 0) {
device = AudioManager.getDeviceForPortId(portId, AudioManager.GET_DEVICES_OUTPUTS);
if (device == null) {
- throw new IllegalArgumentException("invalid portID " + portId);
+ Log.w(TAG, "setCommunicationDevice: invalid portID " + portId);
+ return false;
}
- if (!isValidCommunicationDevice(device)) {
+ if (!AudioDeviceBroker.isValidCommunicationDevice(device)) {
throw new IllegalArgumentException("invalid device type " + device.getType());
}
}
@@ -5939,13 +6015,15 @@
/** @see AudioManager#getCommunicationDevice() */
public int getCommunicationDevice() {
+ int deviceId = 0;
final long ident = Binder.clearCallingIdentity();
- AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
- Binder.restoreCallingIdentity(ident);
- if (device == null) {
- return 0;
+ try {
+ AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
+ deviceId = device != null ? device.getId() : 0;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- return device.getId();
+ return deviceId;
}
/** @see AudioManager#addOnCommunicationDeviceChangedListener(
@@ -7313,6 +7391,7 @@
try {
// if no valid attributes, this volume group is not controllable, throw exception
ensureValidAttributes(avg);
+ sVolumeGroupStates.append(avg.getId(), new VolumeGroupState(avg));
} catch (IllegalArgumentException e) {
// Volume Groups without attributes are not controllable through set/get volume
// using attributes. Do not append them.
@@ -7321,11 +7400,10 @@
}
continue;
}
- sVolumeGroupStates.append(avg.getId(), new VolumeGroupState(avg));
}
for (int i = 0; i < sVolumeGroupStates.size(); i++) {
final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
- vgs.applyAllVolumes();
+ vgs.applyAllVolumes(/* userSwitch= */ false);
}
}
@@ -7338,14 +7416,22 @@
}
}
- private void readVolumeGroupsSettings() {
- if (DEBUG_VOL) {
- Log.v(TAG, "readVolumeGroupsSettings");
- }
- for (int i = 0; i < sVolumeGroupStates.size(); i++) {
- final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
- vgs.readSettings();
- vgs.applyAllVolumes();
+ private void readVolumeGroupsSettings(boolean userSwitch) {
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "readVolumeGroupsSettings userSwitch=" + userSwitch);
+ }
+ for (int i = 0; i < sVolumeGroupStates.size(); i++) {
+ VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
+ // as for STREAM_MUSIC, preserve volume from one user to the next.
+ if (!(userSwitch && vgs.isMusic())) {
+ vgs.clearIndexCache();
+ vgs.readSettings();
+ }
+ vgs.applyAllVolumes(userSwitch);
+ }
+ }
}
}
@@ -7356,7 +7442,7 @@
}
for (int i = 0; i < sVolumeGroupStates.size(); i++) {
final VolumeGroupState vgs = sVolumeGroupStates.valueAt(i);
- vgs.applyAllVolumes();
+ vgs.applyAllVolumes(false/*userSwitch*/);
}
}
@@ -7369,17 +7455,34 @@
}
}
+ private static boolean isCallStream(int stream) {
+ return stream == AudioSystem.STREAM_VOICE_CALL
+ || stream == AudioSystem.STREAM_BLUETOOTH_SCO;
+ }
+
+ private static int getVolumeGroupForStreamType(int stream) {
+ AudioAttributes attributes =
+ AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(stream);
+ if (attributes.equals(new AudioAttributes.Builder().build())) {
+ return AudioVolumeGroup.DEFAULT_VOLUME_GROUP;
+ }
+ return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(
+ attributes, /* fallbackOnDefault= */ false);
+ }
+
// NOTE: Locking order for synchronized objects related to volume management:
// 1 mSettingsLock
- // 2 VolumeGroupState.class
+ // 2 VolumeStreamState.class
private class VolumeGroupState {
private final AudioVolumeGroup mAudioVolumeGroup;
private final SparseIntArray mIndexMap = new SparseIntArray(8);
private int mIndexMin;
private int mIndexMax;
- private int mLegacyStreamType = AudioSystem.STREAM_DEFAULT;
+ private boolean mHasValidStreamType = false;
private int mPublicStreamType = AudioSystem.STREAM_MUSIC;
private AudioAttributes mAudioAttributes = AudioProductStrategy.getDefaultAttributes();
+ private boolean mIsMuted = false;
+ private final String mSettingName;
// No API in AudioSystem to get a device from strategy or from attributes.
// Need a valid public stream type to use current API getDeviceForStream
@@ -7393,20 +7496,22 @@
Log.v(TAG, "VolumeGroupState for " + avg.toString());
}
// mAudioAttributes is the default at this point
- for (final AudioAttributes aa : avg.getAudioAttributes()) {
+ for (AudioAttributes aa : avg.getAudioAttributes()) {
if (!aa.equals(mAudioAttributes)) {
mAudioAttributes = aa;
break;
}
}
- final int[] streamTypes = mAudioVolumeGroup.getLegacyStreamTypes();
+ int[] streamTypes = mAudioVolumeGroup.getLegacyStreamTypes();
+ String streamSettingName = "";
if (streamTypes.length != 0) {
// Uses already initialized MIN / MAX if a stream type is attached to group
- mLegacyStreamType = streamTypes[0];
- for (final int streamType : streamTypes) {
+ for (int streamType : streamTypes) {
if (streamType != AudioSystem.STREAM_DEFAULT
&& streamType < AudioSystem.getNumStreamTypes()) {
mPublicStreamType = streamType;
+ mHasValidStreamType = true;
+ streamSettingName = System.VOLUME_SETTINGS_INT[mPublicStreamType];
break;
}
}
@@ -7416,10 +7521,10 @@
mIndexMin = AudioSystem.getMinVolumeIndexForAttributes(mAudioAttributes);
mIndexMax = AudioSystem.getMaxVolumeIndexForAttributes(mAudioAttributes);
} else {
- Log.e(TAG, "volume group: " + mAudioVolumeGroup.name()
+ throw new IllegalArgumentException("volume group: " + mAudioVolumeGroup.name()
+ " has neither valid attributes nor valid stream types assigned");
- return;
}
+ mSettingName = !streamSettingName.isEmpty() ? streamSettingName : ("volume_" + name());
// Load volume indexes from data base
readSettings();
}
@@ -7432,40 +7537,149 @@
return mAudioVolumeGroup.name();
}
+ /**
+ * Volume group with non null minimum index are considered as non mutable, thus
+ * bijectivity is broken with potential associated stream type.
+ * VOICE_CALL stream has minVolumeIndex > 0 but can be muted directly by an
+ * app that has MODIFY_PHONE_STATE permission.
+ */
+ private boolean isVssMuteBijective(int stream) {
+ return isStreamAffectedByMute(stream)
+ && (getMinIndex() == (mStreamStates[stream].mIndexMin + 5) / 10)
+ && (getMinIndex() == 0 || isCallStream(stream));
+ }
+
+ private boolean isMutable() {
+ return mIndexMin == 0 || (mHasValidStreamType && isVssMuteBijective(mPublicStreamType));
+ }
+ /**
+ * Mute/unmute the volume group
+ * @param muted the new mute state
+ */
+ @GuardedBy("AudioService.VolumeStreamState.class")
+ public boolean mute(boolean muted) {
+ if (!isMutable()) {
+ // Non mutable volume group
+ if (DEBUG_VOL) {
+ Log.d(TAG, "invalid mute on unmutable volume group " + name());
+ }
+ return false;
+ }
+ boolean changed = (mIsMuted != muted);
+ // As for VSS, mute shall apply minIndex to all devices found in IndexMap and default.
+ if (changed) {
+ mIsMuted = muted;
+ applyAllVolumes(false /*userSwitch*/);
+ }
+ return changed;
+ }
+
+ public boolean isMuted() {
+ return mIsMuted;
+ }
+
+ public void adjustVolume(int direction, int flags) {
+ synchronized (VolumeStreamState.class) {
+ int device = getDeviceForVolume();
+ int previousIndex = getIndex(device);
+ if (isMuteAdjust(direction) && !isMutable()) {
+ // Non mutable volume group
+ if (DEBUG_VOL) {
+ Log.d(TAG, "invalid mute on unmutable volume group " + name());
+ }
+ return;
+ }
+ switch (direction) {
+ case AudioManager.ADJUST_TOGGLE_MUTE: {
+ // Note: If muted by volume 0, unmute will restore volume 0.
+ mute(!mIsMuted);
+ break;
+ }
+ case AudioManager.ADJUST_UNMUTE:
+ // Note: If muted by volume 0, unmute will restore volume 0.
+ mute(false);
+ break;
+ case AudioManager.ADJUST_MUTE:
+ // May be already muted by setvolume 0, prevent from setting same value
+ if (previousIndex != 0) {
+ // bypass persist
+ mute(true);
+ }
+ mIsMuted = true;
+ break;
+ case AudioManager.ADJUST_RAISE:
+ // As for stream, RAISE during mute will increment the index
+ setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags);
+ break;
+ case AudioManager.ADJUST_LOWER:
+ // For stream, ADJUST_LOWER on a muted VSS is a no-op
+ // If we decide to unmute on ADJUST_LOWER, cannot fallback on
+ // adjustStreamVolume for group associated to legacy stream type
+ if (isMuted() && previousIndex != 0) {
+ mute(false);
+ } else {
+ int newIndex = Math.max(previousIndex - 1, mIndexMin);
+ setVolumeIndex(newIndex, device, flags);
+ }
+ break;
+ }
+ }
+ }
+
public int getVolumeIndex() {
- return getIndex(getDeviceForVolume());
+ synchronized (VolumeStreamState.class) {
+ return getIndex(getDeviceForVolume());
+ }
}
public void setVolumeIndex(int index, int flags) {
- if (mUseFixedVolume) {
- return;
+ synchronized (VolumeStreamState.class) {
+ if (mUseFixedVolume) {
+ return;
+ }
+ setVolumeIndex(index, getDeviceForVolume(), flags);
}
- setVolumeIndex(index, getDeviceForVolume(), flags);
}
+ @GuardedBy("AudioService.VolumeStreamState.class")
private void setVolumeIndex(int index, int device, int flags) {
- // Set the volume index
- setVolumeIndexInt(index, device, flags);
-
- // Update local cache
- mIndexMap.put(device, index);
-
- // update data base - post a persist volume group msg
- sendMsg(mAudioHandler,
- MSG_PERSIST_VOLUME_GROUP,
- SENDMSG_QUEUE,
- device,
- 0,
- this,
- PERSIST_DELAY);
+ // Update cache & persist (muted by volume 0 shall be persisted)
+ updateVolumeIndex(index, device);
+ // setting non-zero volume for a muted stream unmutes the stream and vice versa,
+ boolean changed = mute(index == 0);
+ if (!changed) {
+ // Set the volume index only if mute operation is a no-op
+ index = getValidIndex(index);
+ setVolumeIndexInt(index, device, flags);
+ }
}
+ @GuardedBy("AudioService.VolumeStreamState.class")
+ public void updateVolumeIndex(int index, int device) {
+ // Filter persistency if already exist and the index has not changed
+ if (mIndexMap.indexOfKey(device) < 0 || mIndexMap.get(device) != index) {
+ // Update local cache
+ mIndexMap.put(device, getValidIndex(index));
+
+ // update data base - post a persist volume group msg
+ sendMsg(mAudioHandler,
+ MSG_PERSIST_VOLUME_GROUP,
+ SENDMSG_QUEUE,
+ device,
+ 0,
+ this,
+ PERSIST_DELAY);
+ }
+ }
+
+ @GuardedBy("AudioService.VolumeStreamState.class")
private void setVolumeIndexInt(int index, int device, int flags) {
// Reflect mute state of corresponding stream by forcing index to 0 if muted
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when
// index is just set to 0 to repect BT requirements
- if (mStreamStates[mPublicStreamType].isFullyMuted()) {
+ if (mHasValidStreamType && isVssMuteBijective(mPublicStreamType)
+ && mStreamStates[mPublicStreamType].isFullyMuted()) {
index = 0;
} else if (mPublicStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0) {
index = 1;
@@ -7474,18 +7688,16 @@
AudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device);
}
- public int getIndex(int device) {
- synchronized (VolumeGroupState.class) {
- int index = mIndexMap.get(device, -1);
- // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
- return (index != -1) ? index : mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
- }
+ @GuardedBy("AudioService.VolumeStreamState.class")
+ private int getIndex(int device) {
+ int index = mIndexMap.get(device, -1);
+ // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
+ return (index != -1) ? index : mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
}
- public boolean hasIndexForDevice(int device) {
- synchronized (VolumeGroupState.class) {
- return (mIndexMap.get(device, -1) != -1);
- }
+ @GuardedBy("AudioService.VolumeStreamState.class")
+ private boolean hasIndexForDevice(int device) {
+ return (mIndexMap.get(device, -1) != -1);
}
public int getMaxIndex() {
@@ -7496,55 +7708,108 @@
return mIndexMin;
}
- private boolean isValidLegacyStreamType() {
- return (mLegacyStreamType != AudioSystem.STREAM_DEFAULT)
- && (mLegacyStreamType < mStreamStates.length);
+ private boolean isValidStream(int stream) {
+ return (stream != AudioSystem.STREAM_DEFAULT) && (stream < mStreamStates.length);
}
- public void applyAllVolumes() {
- synchronized (VolumeGroupState.class) {
- int deviceForStream = AudioSystem.DEVICE_NONE;
- int volumeIndexForStream = 0;
- if (isValidLegacyStreamType()) {
- // Prevent to apply settings twice when group is associated to public stream
- deviceForStream = getDeviceForStream(mLegacyStreamType);
- volumeIndexForStream = getStreamVolume(mLegacyStreamType);
- }
+ public boolean isMusic() {
+ return mHasValidStreamType && mPublicStreamType == AudioSystem.STREAM_MUSIC;
+ }
+
+ public void applyAllVolumes(boolean userSwitch) {
+ String caller = "from vgs";
+ synchronized (VolumeStreamState.class) {
// apply device specific volumes first
- int index;
for (int i = 0; i < mIndexMap.size(); i++) {
- final int device = mIndexMap.keyAt(i);
+ int device = mIndexMap.keyAt(i);
+ int index = mIndexMap.valueAt(i);
+ boolean synced = false;
if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
- index = mIndexMap.valueAt(i);
- if (device == deviceForStream && volumeIndexForStream == index) {
- continue;
+ for (int stream : getLegacyStreamTypes()) {
+ if (isValidStream(stream)) {
+ boolean streamMuted = mStreamStates[stream].mIsMuted;
+ int deviceForStream = getDeviceForStream(stream);
+ int indexForStream =
+ (mStreamStates[stream].getIndex(deviceForStream) + 5) / 10;
+ if (device == deviceForStream) {
+ if (indexForStream == index && (isMuted() == streamMuted)
+ && isVssMuteBijective(stream)) {
+ synced = true;
+ continue;
+ }
+ if (indexForStream != index) {
+ mStreamStates[stream].setIndex(index * 10, device, caller,
+ true /*hasModifyAudioSettings*/);
+ }
+ if ((isMuted() != streamMuted) && isVssMuteBijective(stream)) {
+ mStreamStates[stream].mute(isMuted());
+ }
+ }
+ }
}
- if (DEBUG_VOL) {
- Log.v(TAG, "applyAllVolumes: restore index " + index + " for group "
- + mAudioVolumeGroup.name() + " and device "
- + AudioSystem.getOutputDeviceName(device));
+ if (!synced) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "applyAllVolumes: apply index " + index + ", group "
+ + mAudioVolumeGroup.name() + " and device "
+ + AudioSystem.getOutputDeviceName(device));
+ }
+ setVolumeIndexInt(isMuted() ? 0 : index, device, 0 /*flags*/);
}
- setVolumeIndexInt(index, device, 0 /*flags*/);
}
}
// apply default volume last: by convention , default device volume will be used
// by audio policy manager if no explicit volume is present for a given device type
- index = getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
- if (DEBUG_VOL) {
- Log.v(TAG, "applyAllVolumes: restore default device index " + index
- + " for group " + mAudioVolumeGroup.name());
- }
- if (isValidLegacyStreamType()) {
- int defaultStreamIndex = (mStreamStates[mLegacyStreamType]
- .getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5) / 10;
- if (defaultStreamIndex == index) {
- return;
+ int index = getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
+ boolean synced = false;
+ int deviceForVolume = getDeviceForVolume();
+ boolean forceDeviceSync = userSwitch && (mIndexMap.indexOfKey(deviceForVolume) < 0);
+ for (int stream : getLegacyStreamTypes()) {
+ if (isValidStream(stream)) {
+ boolean streamMuted = mStreamStates[stream].mIsMuted;
+ int defaultStreamIndex = (mStreamStates[stream].getIndex(
+ AudioSystem.DEVICE_OUT_DEFAULT) + 5) / 10;
+ if (forceDeviceSync) {
+ mStreamStates[stream].setIndex(index * 10, deviceForVolume, caller,
+ true /*hasModifyAudioSettings*/);
+ }
+ if (defaultStreamIndex == index && (isMuted() == streamMuted)
+ && isVssMuteBijective(stream)) {
+ synced = true;
+ continue;
+ }
+ if (defaultStreamIndex != index) {
+ mStreamStates[stream].setIndex(
+ index * 10, AudioSystem.DEVICE_OUT_DEFAULT, caller,
+ true /*hasModifyAudioSettings*/);
+ }
+ if ((isMuted() != streamMuted) && isVssMuteBijective(stream)) {
+ mStreamStates[stream].mute(isMuted());
+ }
}
}
- setVolumeIndexInt(index, AudioSystem.DEVICE_OUT_DEFAULT, 0 /*flags*/);
+ if (!synced) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "applyAllVolumes: apply default device index " + index
+ + ", group " + mAudioVolumeGroup.name());
+ }
+ setVolumeIndexInt(
+ isMuted() ? 0 : index, AudioSystem.DEVICE_OUT_DEFAULT, 0 /*flags*/);
+ }
+ if (forceDeviceSync) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "applyAllVolumes: forceDeviceSync index " + index
+ + ", device " + AudioSystem.getOutputDeviceName(deviceForVolume)
+ + ", group " + mAudioVolumeGroup.name());
+ }
+ setVolumeIndexInt(isMuted() ? 0 : index, deviceForVolume, 0);
+ }
}
}
+ public void clearIndexCache() {
+ mIndexMap.clear();
+ }
+
private void persistVolumeGroup(int device) {
if (mUseFixedVolume) {
return;
@@ -7553,21 +7818,19 @@
Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group "
+ mAudioVolumeGroup.name()
+ ", device " + AudioSystem.getOutputDeviceName(device)
- + " and User=" + ActivityManager.getCurrentUser());
+ + " and User=" + getCurrentUserId());
}
boolean success = mSettings.putSystemIntForUser(mContentResolver,
getSettingNameForDevice(device),
getIndex(device),
- UserHandle.USER_CURRENT);
+ isMusic() ? UserHandle.USER_SYSTEM : UserHandle.USER_CURRENT);
if (!success) {
Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name());
}
}
public void readSettings() {
- synchronized (VolumeGroupState.class) {
- // First clear previously loaded (previous user?) settings
- mIndexMap.clear();
+ synchronized (VolumeStreamState.class) {
// force maximum volume on all streams if fixed volume property is set
if (mUseFixedVolume) {
mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
@@ -7582,7 +7845,8 @@
int index;
String name = getSettingNameForDevice(device);
index = mSettings.getSystemIntForUser(
- mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
+ mContentResolver, name, defaultIndex,
+ isMusic() ? UserHandle.USER_SYSTEM : UserHandle.USER_CURRENT);
if (index == -1) {
continue;
}
@@ -7593,13 +7857,14 @@
if (DEBUG_VOL) {
Log.v(TAG, "readSettings: found stored index " + getValidIndex(index)
+ " for group " + mAudioVolumeGroup.name() + ", device: " + name
- + ", User=" + ActivityManager.getCurrentUser());
+ + ", User=" + getCurrentUserId());
}
mIndexMap.put(device, getValidIndex(index));
}
}
}
+ @GuardedBy("AudioService.VolumeStreamState.class")
private int getValidIndex(int index) {
if (index < mIndexMin) {
return mIndexMin;
@@ -7610,15 +7875,17 @@
}
public @NonNull String getSettingNameForDevice(int device) {
- final String suffix = AudioSystem.getOutputDeviceName(device);
+ String suffix = AudioSystem.getOutputDeviceName(device);
if (suffix.isEmpty()) {
- return mAudioVolumeGroup.name();
+ return mSettingName;
}
- return mAudioVolumeGroup.name() + "_" + AudioSystem.getOutputDeviceName(device);
+ return mSettingName + "_" + AudioSystem.getOutputDeviceName(device);
}
private void dump(PrintWriter pw) {
pw.println("- VOLUME GROUP " + mAudioVolumeGroup.name() + ":");
+ pw.print(" Muted: ");
+ pw.println(mIsMuted);
pw.print(" Min: ");
pw.println(mIndexMin);
pw.print(" Max: ");
@@ -7628,9 +7895,9 @@
if (i > 0) {
pw.print(", ");
}
- final int device = mIndexMap.keyAt(i);
+ int device = mIndexMap.keyAt(i);
pw.print(Integer.toHexString(device));
- final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
+ String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
: AudioSystem.getOutputDeviceName(device);
if (!deviceName.isEmpty()) {
pw.print(" (");
@@ -7643,7 +7910,7 @@
pw.println();
pw.print(" Devices: ");
int n = 0;
- final int devices = getDeviceForVolume();
+ int devices = getDeviceForVolume();
for (int device : AudioSystem.DEVICE_OUT_ALL_SET) {
if ((devices & device) == device) {
if (n++ > 0) {
@@ -7652,6 +7919,10 @@
pw.print(AudioSystem.getOutputDeviceName(device));
}
}
+ pw.println();
+ pw.print(" Streams: ");
+ Arrays.stream(getLegacyStreamTypes())
+ .forEach(stream -> pw.print(AudioSystem.streamToString(stream) + " "));
}
}
@@ -7663,13 +7934,14 @@
// 4 VolumeStreamState.class
private class VolumeStreamState {
private final int mStreamType;
+ private VolumeGroupState mVolumeGroupState = null;
private int mIndexMin;
// min index when user doesn't have permission to change audio settings
private int mIndexMinNoPerm;
private int mIndexMax;
- private boolean mIsMuted;
- private boolean mIsMutedInternally;
+ private boolean mIsMuted = false;
+ private boolean mIsMutedInternally = false;
private String mVolumeIndexSettingName;
@NonNull private Set<Integer> mObservedDeviceSet = new TreeSet<>();
@@ -7727,6 +7999,15 @@
}
/**
+ * Associate a {@link volumeGroupState} on the {@link VolumeStreamState}.
+ * <p> It helps to synchronize the index, mute attributes on the maching
+ * {@link volumeGroupState}
+ * @param volumeGroupState matching the {@link VolumeStreamState}
+ */
+ public void setVolumeGroupState(VolumeGroupState volumeGroupState) {
+ mVolumeGroupState = volumeGroupState;
+ }
+ /**
* Update the minimum index that can be used without MODIFY_AUDIO_SETTINGS permission
* @param index minimum index expressed in "UI units", i.e. no 10x factor
*/
@@ -7984,6 +8265,9 @@
}
}
if (changed) {
+ // If associated to volume group, update group cache
+ updateVolumeGroupIndex(device, /* forceMuteState= */ false);
+
oldIndex = (oldIndex + 5) / 10;
index = (index + 5) / 10;
// log base stream changes to the event log
@@ -8086,6 +8370,28 @@
}
}
+ // If associated to volume group, update group cache
+ private void updateVolumeGroupIndex(int device, boolean forceMuteState) {
+ synchronized (VolumeStreamState.class) {
+ if (mVolumeGroupState != null) {
+ int groupIndex = (getIndex(device) + 5) / 10;
+ if (DEBUG_VOL) {
+ Log.d(TAG, "updateVolumeGroupIndex for stream " + mStreamType
+ + ", muted=" + mIsMuted + ", device=" + device + ", index="
+ + getIndex(device) + ", group " + mVolumeGroupState.name()
+ + " Muted=" + mVolumeGroupState.isMuted() + ", Index=" + groupIndex
+ + ", forceMuteState=" + forceMuteState);
+ }
+ mVolumeGroupState.updateVolumeIndex(groupIndex, device);
+ // Only propage mute of stream when applicable
+ if (mIndexMin == 0 || isCallStream(mStreamType)) {
+ // For call stream, align mute only when muted, not when index is set to 0
+ mVolumeGroupState.mute(forceMuteState ? mIsMuted : groupIndex == 0);
+ }
+ }
+ }
+ }
+
/**
* Mute/unmute the stream
* @param state the new mute state
@@ -8094,27 +8400,10 @@
public boolean mute(boolean state) {
boolean changed = false;
synchronized (VolumeStreamState.class) {
- if (state != mIsMuted) {
- changed = true;
- mIsMuted = state;
-
- // Set the new mute volume. This propagates the values to
- // the audio system, otherwise the volume won't be changed
- // at the lower level.
- sendMsg(mAudioHandler,
- MSG_SET_ALL_VOLUMES,
- SENDMSG_QUEUE,
- 0,
- 0,
- this, 0);
- }
+ changed = mute(state, true);
}
if (changed) {
- // Stream mute changed, fire the intent.
- Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
- intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
- sendBroadcastToAll(intent);
+ broadcastMuteSetting(mStreamType, state);
}
return changed;
}
@@ -8146,6 +8435,44 @@
return mIsMuted || mIsMutedInternally;
}
+ /**
+ * Mute/unmute the stream
+ * @param state the new mute state
+ * @param apply true to propagate to HW, or false just to update the cache. May be needed
+ * to mute a stream and its aliases as applyAllVolume will force settings to aliases.
+ * It prevents unnecessary calls to {@see AudioSystem#setStreamVolume}
+ * @return true if the mute state was changed
+ */
+ public boolean mute(boolean state, boolean apply) {
+ synchronized (VolumeStreamState.class) {
+ boolean changed = state != mIsMuted;
+ if (changed) {
+ mIsMuted = state;
+ if (apply) {
+ doMute();
+ }
+ }
+ return changed;
+ }
+ }
+
+ public void doMute() {
+ synchronized (VolumeStreamState.class) {
+ // If associated to volume group, update group cache
+ updateVolumeGroupIndex(getDeviceForStream(mStreamType), /* forceMuteState= */ true);
+
+ // Set the new mute volume. This propagates the values to
+ // the audio system, otherwise the volume won't be changed
+ // at the lower level.
+ sendMsg(mAudioHandler,
+ MSG_SET_ALL_VOLUMES,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ this, 0);
+ }
+ }
+
public int getStreamType() {
return mStreamType;
}
@@ -8215,6 +8542,9 @@
pw.println();
pw.print(" Devices: ");
pw.print(AudioSystem.deviceSetToString(getDeviceSetForStream(mStreamType)));
+ pw.println();
+ pw.print(" Volume Group: ");
+ pw.println(mVolumeGroupState != null ? mVolumeGroupState.name() : "n/a");
}
}
@@ -9957,7 +10287,8 @@
mPendingVolumeCommand.mIndex,
mPendingVolumeCommand.mFlags,
mPendingVolumeCommand.mDevice,
- callingPackage, true /*hasModifyAudioSettings*/);
+ callingPackage, true /*hasModifyAudioSettings*/,
+ true /*canChangeMute*/);
mPendingVolumeCommand = null;
}
}
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index c2c3f02..6cbe03e 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -17,7 +17,6 @@
package com.android.server.audio;
import android.annotation.NonNull;
-import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -221,6 +220,7 @@
static final int VOL_SET_GROUP_VOL = 8;
static final int VOL_MUTE_STREAM_INT = 9;
static final int VOL_SET_LE_AUDIO_VOL = 10;
+ static final int VOL_ADJUST_GROUP_VOL = 11;
final int mOp;
final int mStream;
@@ -228,7 +228,6 @@
final int mVal2;
final String mCaller;
final String mGroupName;
- final AudioAttributes mAudioAttributes;
/** used for VOL_ADJUST_VOL_UID,
* VOL_ADJUST_SUGG_VOL,
@@ -241,7 +240,6 @@
mVal2 = val2;
mCaller = caller;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -254,7 +252,6 @@
mStream = -1;
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -267,7 +264,6 @@
mStream = -1;
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -280,7 +276,6 @@
// unused
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -293,19 +288,18 @@
// unused
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
- /** used for VOL_SET_GROUP_VOL */
- VolumeEvent(int op, AudioAttributes aa, String group, int index, int flags, String caller) {
+ /** used for VOL_SET_GROUP_VOL,
+ * VOL_ADJUST_GROUP_VOL */
+ VolumeEvent(int op, String group, int index, int flags, String caller) {
mOp = op;
mStream = -1;
mVal1 = index;
mVal2 = flags;
mCaller = caller;
mGroupName = group;
- mAudioAttributes = aa;
logMetricEvent();
}
@@ -317,7 +311,6 @@
mVal2 = 0;
mCaller = null;
mGroupName = null;
- mAudioAttributes = null;
logMetricEvent();
}
@@ -359,6 +352,15 @@
.record();
return;
}
+ case VOL_ADJUST_GROUP_VOL:
+ new MediaMetrics.Item(mMetricsId)
+ .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
+ .set(MediaMetrics.Property.DIRECTION, mVal1 > 0 ? "up" : "down")
+ .set(MediaMetrics.Property.EVENT, "adjustVolumeGroupVolume")
+ .set(MediaMetrics.Property.FLAGS, mVal2)
+ .set(MediaMetrics.Property.GROUP, mGroupName)
+ .record();
+ return;
case VOL_SET_STREAM_VOL:
new MediaMetrics.Item(mMetricsId)
.set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
@@ -410,7 +412,6 @@
return;
case VOL_SET_GROUP_VOL:
new MediaMetrics.Item(mMetricsId)
- .set(MediaMetrics.Property.ATTRIBUTES, mAudioAttributes.toString())
.set(MediaMetrics.Property.CALLING_PACKAGE, mCaller)
.set(MediaMetrics.Property.EVENT, "setVolumeIndexForAttributes")
.set(MediaMetrics.Property.FLAGS, mVal2)
@@ -436,6 +437,13 @@
.append(" flags:0x").append(Integer.toHexString(mVal2))
.append(") from ").append(mCaller)
.toString();
+ case VOL_ADJUST_GROUP_VOL:
+ return new StringBuilder("adjustVolumeGroupVolume(group:")
+ .append(mGroupName)
+ .append(" dir:").append(AudioManager.adjustToString(mVal1))
+ .append(" flags:0x").append(Integer.toHexString(mVal2))
+ .append(") from ").append(mCaller)
+ .toString();
case VOL_ADJUST_STREAM_VOL:
return new StringBuilder("adjustStreamVolume(stream:")
.append(AudioSystem.streamToString(mStream))
@@ -484,8 +492,7 @@
.append(" stream:").append(AudioSystem.streamToString(mStream))
.toString();
case VOL_SET_GROUP_VOL:
- return new StringBuilder("setVolumeIndexForAttributes(attr:")
- .append(mAudioAttributes.toString())
+ return new StringBuilder("setVolumeIndexForAttributes(group:")
.append(" group: ").append(mGroupName)
.append(" index:").append(mVal1)
.append(" flags:0x").append(Integer.toHexString(mVal2))
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 4d55d4e..39acaee 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -150,8 +150,9 @@
= new ArraySet<>();
// Just the packages from mEnabledServicesForCurrentProfiles
private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
- // List of enabled packages that have nevertheless asked not to be run
- private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
+ // Per user id, list of enabled packages that have nevertheless asked not to be run
+ private final android.util.SparseSetArray<ComponentName> mSnoozing =
+ new android.util.SparseSetArray<>();
// List of approved packages or components (by user, then by primary/secondary) that are
// allowed to be bound as managed services. A package or component appearing in this list does
@@ -386,10 +387,15 @@
}
}
- pw.println(" Snoozed " + getCaption() + "s (" +
- mSnoozingForCurrentProfiles.size() + "):");
- for (ComponentName name : mSnoozingForCurrentProfiles) {
- pw.println(" " + name.flattenToShortString());
+ synchronized (mSnoozing) {
+ pw.println(" Snoozed " + getCaption() + "s ("
+ + mSnoozing.size() + "):");
+ for (int i = 0; i < mSnoozing.size(); i++) {
+ pw.println(" User: " + mSnoozing.keyAt(i));
+ for (ComponentName name : mSnoozing.valuesAt(i)) {
+ pw.println(" " + name.flattenToShortString());
+ }
+ }
}
}
@@ -431,8 +437,16 @@
}
}
- for (ComponentName name : mSnoozingForCurrentProfiles) {
- name.dumpDebug(proto, ManagedServicesProto.SNOOZED);
+ synchronized (mSnoozing) {
+ for (int i = 0; i < mSnoozing.size(); i++) {
+ long token = proto.start(ManagedServicesProto.SNOOZED);
+ proto.write(ManagedServicesProto.SnoozedServices.USER_ID,
+ mSnoozing.keyAt(i));
+ for (ComponentName name : mSnoozing.valuesAt(i)) {
+ name.dumpDebug(proto, ManagedServicesProto.SnoozedServices.SNOOZED);
+ }
+ proto.end(token);
+ }
}
}
@@ -975,6 +989,9 @@
synchronized (mApproved) {
mApproved.remove(user);
}
+ synchronized (mSnoozing) {
+ mSnoozing.remove(user);
+ }
rebindServices(true, user);
}
@@ -1066,15 +1083,17 @@
}
protected void setComponentState(ComponentName component, int userId, boolean enabled) {
- boolean previous = !mSnoozingForCurrentProfiles.contains(component);
- if (previous == enabled) {
- return;
- }
+ synchronized (mSnoozing) {
+ boolean previous = !mSnoozing.contains(userId, component);
+ if (previous == enabled) {
+ return;
+ }
- if (enabled) {
- mSnoozingForCurrentProfiles.remove(component);
- } else {
- mSnoozingForCurrentProfiles.add(component);
+ if (enabled) {
+ mSnoozing.remove(userId, component);
+ } else {
+ mSnoozing.add(userId, component);
+ }
}
// State changed
@@ -1287,7 +1306,10 @@
}
final Set<ComponentName> add = new HashSet<>(userComponents);
- add.removeAll(mSnoozingForCurrentProfiles);
+ ArraySet<ComponentName> snoozed = mSnoozing.get(userId);
+ if (snoozed != null) {
+ add.removeAll(snoozed);
+ }
componentsToBind.put(userId, add);
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 7252545..7489f80 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -709,7 +709,8 @@
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
return r != null
- ? r.getRequestedOrientation() : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ ? r.getOverrideOrientation()
+ : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6b01a77..2dad910 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -439,6 +439,9 @@
// finished destroying itself.
private static final int DESTROY_TIMEOUT = 10 * 1000;
+ // Rounding tolerance to be used in aspect ratio computations
+ private static final float ASPECT_RATIO_ROUNDING_TOLERANCE = 0.005f;
+
final ActivityTaskManagerService mAtmService;
@NonNull
final ActivityInfo info; // activity info provided by developer in AndroidManifest
@@ -1165,8 +1168,10 @@
pw.println(prefix + "mVoiceInteraction=true");
}
pw.print(prefix); pw.print("mOccludesParent="); pw.println(mOccludesParent);
- pw.print(prefix); pw.print("mOrientation=");
- pw.println(ActivityInfo.screenOrientationToString(mOrientation));
+ pw.print(prefix); pw.print("overrideOrientation=");
+ pw.println(ActivityInfo.screenOrientationToString(getOverrideOrientation()));
+ pw.print(prefix); pw.print("requestedOrientation=");
+ pw.println(ActivityInfo.screenOrientationToString(super.getOverrideOrientation()));
pw.println(prefix + "mVisibleRequested=" + mVisibleRequested
+ " mVisible=" + mVisible + " mClientVisible=" + isClientVisible()
+ ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
@@ -1964,6 +1969,15 @@
new ComponentName(info.packageName, info.targetActivity);
}
+ // Don't move below setActivityType since it triggers onConfigurationChange ->
+ // resolveOverrideConfiguration that requires having mLetterboxUiController initialised.
+ // Don't move below setOrientation(info.screenOrientation) since it triggers
+ // getOverrideOrientation that requires having mLetterboxUiController
+ // initialised.
+ mLetterboxUiController = new LetterboxUiController(mWmService, this);
+ mCameraCompatControlEnabled = mWmService.mContext.getResources()
+ .getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
+
mTargetSdk = info.applicationInfo.targetSdkVersion;
mShowForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0;
setOrientation(info.screenOrientation);
@@ -2084,12 +2098,6 @@
launchMode = aInfo.launchMode;
- // Don't move below setActivityType since it triggers onConfigurationChange ->
- // resolveOverrideConfiguration that requires having mLetterboxUiController initialised.
- mLetterboxUiController = new LetterboxUiController(mWmService, this);
- mCameraCompatControlEnabled = mWmService.mContext.getResources()
- .getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
-
setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord);
immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
@@ -2486,7 +2494,8 @@
if (topAttached != null) {
if (topAttached.isSnapshotCompatible(snapshot)
// This trampoline must be the same rotation.
- && mDisplayContent.getDisplayRotation().rotationForOrientation(mOrientation,
+ && mDisplayContent.getDisplayRotation().rotationForOrientation(
+ getOverrideOrientation(),
mDisplayContent.getRotation()) == snapshot.getRotation()) {
return STARTING_WINDOW_TYPE_SNAPSHOT;
}
@@ -7704,13 +7713,13 @@
return mLetterboxUiController.getInheritedOrientation();
}
}
- if (mOrientation == SCREEN_ORIENTATION_BEHIND && task != null) {
+ if (task != null && getOverrideOrientation() == SCREEN_ORIENTATION_BEHIND) {
// We use Task here because we want to be consistent with what happens in
// multi-window mode where other tasks orientations are ignored.
final ActivityRecord belowCandidate = task.getActivity(
- a -> a.mOrientation != SCREEN_ORIENTATION_UNSET && !a.finishing
- && a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND, this,
- false /* includeBoundary */, true /* traverseTopToBottom */);
+ a -> a.canDefineOrientationForActivitiesAbove() /* callback */,
+ this /* boundary */, false /* includeBoundary */,
+ true /* traverseTopToBottom */);
if (belowCandidate != null) {
return belowCandidate.getRequestedConfigurationOrientation(forDisplay);
}
@@ -7718,6 +7727,19 @@
return super.getRequestedConfigurationOrientation(forDisplay);
}
+ /**
+ * Whether this activity can be used as an orientation source for activities above with
+ * {@link SCREEN_ORIENTATION_BEHIND}.
+ */
+ boolean canDefineOrientationForActivitiesAbove() {
+ if (finishing) {
+ return false;
+ }
+ final int overrideOrientation = getOverrideOrientation();
+ return overrideOrientation != SCREEN_ORIENTATION_UNSET
+ && overrideOrientation != SCREEN_ORIENTATION_BEHIND;
+ }
+
@Override
void onCancelFixedRotationTransform(int originalDisplayRotation) {
if (this != mDisplayContent.getLastOrientationSource()) {
@@ -7744,7 +7766,7 @@
}
}
- void setRequestedOrientation(int requestedOrientation) {
+ void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
return;
}
@@ -7789,7 +7811,7 @@
// Allow app to specify orientation regardless of its visibility state if the current
// candidate want us to use orientation behind. I.e. the visible app on-top of this one
// wants us to use the orientation of the app behind it.
- return mOrientation;
+ return getOverrideOrientation();
}
// The {@link ActivityRecord} should only specify an orientation when it is not closing.
@@ -7797,15 +7819,31 @@
// task being started in the wrong orientation during the transition.
if (!getDisplayContent().mClosingApps.contains(this)
&& (isVisibleRequested() || getDisplayContent().mOpeningApps.contains(this))) {
- return mOrientation;
+ return getOverrideOrientation();
}
return SCREEN_ORIENTATION_UNSET;
}
- /** Returns the app's preferred orientation regardless of its currently visibility state. */
+ /**
+ * Returns the app's preferred orientation regardless of its current visibility state taking
+ * into account orientation per-app overrides applied by the device manufacturers.
+ */
+ @Override
+ protected int getOverrideOrientation() {
+ return mLetterboxUiController.overrideOrientationIfNeeded(super.getOverrideOrientation());
+ }
+
+ /**
+ * Returns the app's preferred orientation regardless of its currently visibility state. This
+ * is used to return a requested value to an app if they call {@link
+ * android.app.Activity#getRequestedOrientation} since {@link #getOverrideOrientation} value
+ * with override can confuse an app if it's different from what they requested with {@link
+ * android.app.Activity#setRequestedOrientation}.
+ */
+ @ActivityInfo.ScreenOrientation
int getRequestedOrientation() {
- return mOrientation;
+ return super.getOverrideOrientation();
}
/**
@@ -8357,8 +8395,8 @@
// If orientation is respected when insets are applied, then stableBounds will be empty.
boolean orientationRespectedWithInsets =
orientationRespectedWithInsets(parentBounds, stableBounds);
- if (orientationRespectedWithInsets
- && handlesOrientationChangeFromDescendant(mOrientation)) {
+ if (orientationRespectedWithInsets && handlesOrientationChangeFromDescendant(
+ getOverrideOrientation())) {
// No need to letterbox because of fixed orientation. Display will handle
// fixed-orientation requests and a display rotation is enough to respect requested
// orientation with insets applied.
@@ -8915,7 +8953,7 @@
int activityWidth = containingAppWidth;
int activityHeight = containingAppHeight;
- if (containingRatio > desiredAspectRatio) {
+ if (containingRatio - desiredAspectRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) {
if (containingAppWidth < containingAppHeight) {
// Width is the shorter side, so we use that to figure-out what the max. height
// should be given the aspect ratio.
@@ -8925,7 +8963,7 @@
// should be given the aspect ratio.
activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
}
- } else if (containingRatio < desiredAspectRatio) {
+ } else if (desiredAspectRatio - containingRatio > ASPECT_RATIO_ROUNDING_TOLERANCE) {
boolean adjustWidth;
switch (getRequestedConfigurationOrientation()) {
case ORIENTATION_LANDSCAPE:
@@ -9003,7 +9041,8 @@
}
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
- && !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation())) {
+ && !ActivityInfo.isFixedOrientationPortrait(
+ getOverrideOrientation())) {
return info.getMinAspectRatio();
}
diff --git a/services/core/java/com/android/server/wm/DeviceStateController.java b/services/core/java/com/android/server/wm/DeviceStateController.java
index a6f8557..7d9a4ec 100644
--- a/services/core/java/com/android/server/wm/DeviceStateController.java
+++ b/services/core/java/com/android/server/wm/DeviceStateController.java
@@ -16,80 +16,107 @@
package com.android.server.wm;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Handler;
import android.os.HandlerExecutor;
+import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
+import java.util.ArrayList;
+import java.util.List;
import java.util.function.Consumer;
/**
- * Class that registers callbacks with the {@link DeviceStateManager} and
- * responds to fold state changes by forwarding such events to a delegate.
+ * Class that registers callbacks with the {@link DeviceStateManager} and responds to device
+ * changes.
*/
-final class DeviceStateController {
+final class DeviceStateController implements DeviceStateManager.DeviceStateCallback {
+
+ @NonNull
private final DeviceStateManager mDeviceStateManager;
- private final Context mContext;
+ @NonNull
+ private final int[] mOpenDeviceStates;
+ @NonNull
+ private final int[] mHalfFoldedDeviceStates;
+ @NonNull
+ private final int[] mFoldedDeviceStates;
+ @NonNull
+ private final int[] mRearDisplayDeviceStates;
+ @NonNull
+ private final int[] mReverseRotationAroundZAxisStates;
+ @NonNull
+ private final List<Consumer<DeviceState>> mDeviceStateCallbacks = new ArrayList<>();
- private FoldStateListener mDeviceStateListener;
+ @Nullable
+ private DeviceState mLastDeviceState;
+ private int mCurrentState;
- public enum FoldState {
- UNKNOWN, OPEN, FOLDED, HALF_FOLDED
+ public enum DeviceState {
+ UNKNOWN, OPEN, FOLDED, HALF_FOLDED, REAR,
}
- DeviceStateController(Context context, Handler handler, Consumer<FoldState> delegate) {
- mContext = context;
- mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
+ DeviceStateController(@NonNull Context context, @NonNull Handler handler) {
+ mDeviceStateManager = context.getSystemService(DeviceStateManager.class);
+
+ mOpenDeviceStates = context.getResources()
+ .getIntArray(R.array.config_openDeviceStates);
+ mHalfFoldedDeviceStates = context.getResources()
+ .getIntArray(R.array.config_halfFoldedDeviceStates);
+ mFoldedDeviceStates = context.getResources()
+ .getIntArray(R.array.config_foldedDeviceStates);
+ mRearDisplayDeviceStates = context.getResources()
+ .getIntArray(R.array.config_rearDisplayDeviceStates);
+ mReverseRotationAroundZAxisStates = context.getResources()
+ .getIntArray(R.array.config_deviceStatesToReverseDefaultDisplayRotationAroundZAxis);
+
if (mDeviceStateManager != null) {
- mDeviceStateListener = new FoldStateListener(mContext, delegate);
- mDeviceStateManager
- .registerCallback(new HandlerExecutor(handler),
- mDeviceStateListener);
+ mDeviceStateManager.registerCallback(new HandlerExecutor(handler), this);
}
}
void unregisterFromDeviceStateManager() {
- if (mDeviceStateListener != null) {
- mDeviceStateManager.unregisterCallback(mDeviceStateListener);
+ if (mDeviceStateManager != null) {
+ mDeviceStateManager.unregisterCallback(this);
}
}
+ void registerDeviceStateCallback(@NonNull Consumer<DeviceState> callback) {
+ mDeviceStateCallbacks.add(callback);
+ }
+
/**
- * A listener for half-fold device state events that dispatches state changes to a delegate.
+ * @return true if the rotation direction on the Z axis should be reversed.
*/
- static final class FoldStateListener implements DeviceStateManager.DeviceStateCallback {
+ boolean shouldReverseRotationDirectionAroundZAxis() {
+ return ArrayUtils.contains(mReverseRotationAroundZAxisStates, mCurrentState);
+ }
- private final int[] mHalfFoldedDeviceStates;
- private final int[] mFoldedDeviceStates;
+ @Override
+ public void onStateChanged(int state) {
+ mCurrentState = state;
- @Nullable
- private FoldState mLastResult;
- private final Consumer<FoldState> mDelegate;
-
- FoldStateListener(Context context, Consumer<FoldState> delegate) {
- mFoldedDeviceStates = context.getResources().getIntArray(
- com.android.internal.R.array.config_foldedDeviceStates);
- mHalfFoldedDeviceStates = context.getResources().getIntArray(
- com.android.internal.R.array.config_halfFoldedDeviceStates);
- mDelegate = delegate;
+ final DeviceState deviceState;
+ if (ArrayUtils.contains(mHalfFoldedDeviceStates, state)) {
+ deviceState = DeviceState.HALF_FOLDED;
+ } else if (ArrayUtils.contains(mFoldedDeviceStates, state)) {
+ deviceState = DeviceState.FOLDED;
+ } else if (ArrayUtils.contains(mRearDisplayDeviceStates, state)) {
+ deviceState = DeviceState.REAR;
+ } else if (ArrayUtils.contains(mOpenDeviceStates, state)) {
+ deviceState = DeviceState.OPEN;
+ } else {
+ deviceState = DeviceState.UNKNOWN;
}
- @Override
- public void onStateChanged(int state) {
- final boolean halfFolded = ArrayUtils.contains(mHalfFoldedDeviceStates, state);
- FoldState result;
- if (halfFolded) {
- result = FoldState.HALF_FOLDED;
- } else {
- final boolean folded = ArrayUtils.contains(mFoldedDeviceStates, state);
- result = folded ? FoldState.FOLDED : FoldState.OPEN;
- }
- if (mLastResult == null || !mLastResult.equals(result)) {
- mLastResult = result;
- mDelegate.accept(result);
+ if (mLastDeviceState == null || !mLastDeviceState.equals(deviceState)) {
+ mLastDeviceState = deviceState;
+
+ for (Consumer<DeviceState> callback : mDeviceStateCallbacks) {
+ callback.accept(mLastDeviceState);
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index af5bd14..fad2dda 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -93,7 +93,7 @@
DisplayArea(WindowManagerService wms, Type type, String name, int featureId) {
super(wms);
// TODO(display-area): move this up to ConfigurationContainer
- mOrientation = SCREEN_ORIENTATION_UNSET;
+ setOverrideOrientation(SCREEN_ORIENTATION_UNSET);
mType = type;
mName = name;
mFeatureId = featureId;
@@ -165,7 +165,8 @@
// If this is set to ignore the orientation request, we don't propagate descendant
// orientation request.
final int orientation = requestingContainer != null
- ? requestingContainer.mOrientation : SCREEN_ORIENTATION_UNSET;
+ ? requestingContainer.getOverrideOrientation()
+ : SCREEN_ORIENTATION_UNSET;
return !getIgnoreOrientationRequest(orientation)
&& super.onDescendantOrientationChanged(requestingContainer);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9af1b2b..5767730 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -27,6 +27,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -1125,14 +1126,18 @@
mWmService.mAtmService.getRecentTasks().getInputListener());
}
- mDisplayPolicy = new DisplayPolicy(mWmService, this);
- mDisplayRotation = new DisplayRotation(mWmService, this, mDisplayInfo.address);
+ mDeviceStateController = new DeviceStateController(mWmService.mContext, mWmService.mH);
- mDeviceStateController = new DeviceStateController(mWmService.mContext, mWmService.mH,
- newFoldState -> {
+ mDisplayPolicy = new DisplayPolicy(mWmService, this);
+ mDisplayRotation = new DisplayRotation(mWmService, this, mDisplayInfo.address,
+ mDeviceStateController);
+
+ final Consumer<DeviceStateController.DeviceState> deviceStateConsumer =
+ (@NonNull DeviceStateController.DeviceState newFoldState) -> {
mDisplaySwitchTransitionLauncher.foldStateChanged(newFoldState);
mDisplayRotation.foldStateChanged(newFoldState);
- });
+ };
+ mDeviceStateController.registerDeviceStateCallback(deviceStateConsumer);
mCloseToSquareMaxAspectRatio = mWmService.mContext.getResources().getFloat(
R.dimen.config_closeToSquareDisplayMaxAspectRatio);
@@ -1572,7 +1577,8 @@
// If display rotation class tells us that it doesn't consider app requested orientation,
// this display won't rotate just because of an app changes its requested orientation. Thus
// it indicates that this display chooses not to handle this request.
- final int orientation = requestingContainer != null ? requestingContainer.mOrientation
+ final int orientation = requestingContainer != null
+ ? requestingContainer.getOverrideOrientation()
: SCREEN_ORIENTATION_UNSET;
final boolean handled = handlesOrientationChangeFromDescendant(orientation);
if (config == null) {
@@ -1698,14 +1704,17 @@
if (mTransitionController.useShellTransitionsRotation()) {
return ROTATION_UNDEFINED;
}
+ final int activityOrientation = r.getOverrideOrientation();
if (!WindowManagerService.ENABLE_FIXED_ROTATION_TRANSFORM
- || getIgnoreOrientationRequest(r.mOrientation)) {
+ || getIgnoreOrientationRequest(activityOrientation)) {
return ROTATION_UNDEFINED;
}
- if (r.mOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ if (activityOrientation == ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
+ // TODO(b/266280737): Use ActivityRecord#canDefineOrientationForActivitiesAbove
final ActivityRecord nextCandidate = getActivity(
- a -> a.mOrientation != SCREEN_ORIENTATION_UNSET
- && a.mOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND,
+ a -> a.getOverrideOrientation() != SCREEN_ORIENTATION_UNSET
+ && a.getOverrideOrientation()
+ != ActivityInfo.SCREEN_ORIENTATION_BEHIND,
r, false /* includeBoundary */, true /* traverseTopToBottom */);
if (nextCandidate != null) {
r = nextCandidate;
@@ -2723,6 +2732,15 @@
final int orientation = super.getOrientation();
if (!handlesOrientationChangeFromDescendant(orientation)) {
+ ActivityRecord topActivity = topRunningActivity(/* considerKeyguardState= */ true);
+ if (topActivity != null && topActivity.mLetterboxUiController
+ .shouldUseDisplayLandscapeNaturalOrientation()) {
+ ProtoLog.v(WM_DEBUG_ORIENTATION,
+ "Display id=%d is ignoring orientation request for %d, return %d"
+ + " following a per-app override for %s",
+ mDisplayId, orientation, SCREEN_ORIENTATION_LANDSCAPE, topActivity);
+ return SCREEN_ORIENTATION_LANDSCAPE;
+ }
mLastOrientationSource = null;
// Return SCREEN_ORIENTATION_UNSPECIFIED so that Display respect sensor rotation
ProtoLog.v(WM_DEBUG_ORIENTATION,
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f8fd2b9..cf7d5d9 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2007,7 +2007,8 @@
dc.getDisplayPolicy().simulateLayoutDisplay(df);
final InsetsState insetsState = df.mInsetsState;
final Rect displayFrame = insetsState.getDisplayFrame();
- final Insets decor = calculateDecorInsetsWithInternalTypes(insetsState);
+ final Insets decor = insetsState.calculateInsets(displayFrame, DECOR_TYPES,
+ true /* ignoreVisibility */);
final Insets statusBar = insetsState.calculateInsets(displayFrame,
Type.statusBars(), true /* ignoreVisibility */);
mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom);
@@ -2039,17 +2040,8 @@
}
}
- // TODO (b/235842600): Use public type once we can treat task bar as navigation bar.
- static final int[] INTERNAL_DECOR_TYPES;
- static {
- final ArraySet<Integer> decorTypes = InsetsState.toInternalType(
- Type.displayCutout() | Type.navigationBars());
- decorTypes.remove(ITYPE_EXTRA_NAVIGATION_BAR);
- INTERNAL_DECOR_TYPES = new int[decorTypes.size()];
- for (int i = 0; i < INTERNAL_DECOR_TYPES.length; i++) {
- INTERNAL_DECOR_TYPES[i] = decorTypes.valueAt(i);
- }
- }
+
+ static final int DECOR_TYPES = Type.displayCutout() | Type.navigationBars();
private final DisplayContent mDisplayContent;
private final Info[] mInfoForRotation = new Info[4];
@@ -2076,20 +2068,6 @@
info.mNeedUpdate = true;
}
}
-
- // TODO (b/235842600): Remove this method once we can treat task bar as navigation bar.
- private static Insets calculateDecorInsetsWithInternalTypes(InsetsState state) {
- final Rect frame = state.getDisplayFrame();
- Insets insets = Insets.NONE;
- for (int i = INTERNAL_DECOR_TYPES.length - 1; i >= 0; i--) {
- final InsetsSource source = state.peekSource(INTERNAL_DECOR_TYPES[i]);
- if (source != null) {
- insets = Insets.max(source.calculateInsets(frame, true /* ignoreVisibility */),
- insets);
- }
- }
- return insets;
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index e6d8b3d..3404279 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -41,6 +41,7 @@
import android.annotation.AnimRes;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ContentResolver;
@@ -117,6 +118,8 @@
private SettingsObserver mSettingsObserver;
@Nullable
private FoldController mFoldController;
+ @NonNull
+ private final DeviceStateController mDeviceStateController;
@ScreenOrientation
private int mCurrentAppOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
@@ -218,21 +221,24 @@
private boolean mDemoRotationLock;
DisplayRotation(WindowManagerService service, DisplayContent displayContent,
- DisplayAddress displayAddress) {
+ DisplayAddress displayAddress, @NonNull DeviceStateController deviceStateController) {
this(service, displayContent, displayAddress, displayContent.getDisplayPolicy(),
- service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
+ service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock(),
+ deviceStateController);
}
@VisibleForTesting
DisplayRotation(WindowManagerService service, DisplayContent displayContent,
DisplayAddress displayAddress, DisplayPolicy displayPolicy,
- DisplayWindowSettings displayWindowSettings, Context context, Object lock) {
+ DisplayWindowSettings displayWindowSettings, Context context, Object lock,
+ @NonNull DeviceStateController deviceStateController) {
mService = service;
mDisplayContent = displayContent;
mDisplayPolicy = displayPolicy;
mDisplayWindowSettings = displayWindowSettings;
mContext = context;
mLock = lock;
+ mDeviceStateController = deviceStateController;
isDefaultDisplay = displayContent.isDefaultDisplay;
mCompatPolicyForImmersiveApps = initImmersiveAppCompatPolicy(service, displayContent);
@@ -243,11 +249,13 @@
mDeskDockRotation = readRotation(R.integer.config_deskDockRotation);
mUndockedHdmiRotation = readRotation(R.integer.config_undockedHdmiRotation);
- mRotation = readDefaultDisplayRotation(displayAddress);
+ int defaultRotation = readDefaultDisplayRotation(displayAddress);
+ mRotation = defaultRotation;
if (isDefaultDisplay) {
final Handler uiHandler = UiThread.getHandler();
- mOrientationListener = new OrientationListener(mContext, uiHandler);
+ mOrientationListener =
+ new OrientationListener(mContext, uiHandler, defaultRotation);
mOrientationListener.setCurrentRotation(mRotation);
mSettingsObserver = new SettingsObserver(uiHandler);
mSettingsObserver.observe();
@@ -1137,6 +1145,15 @@
int sensorRotation = mOrientationListener != null
? mOrientationListener.getProposedRotation() // may be -1
: -1;
+ if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()) {
+ // Flipping 270 and 90 has the same effect as changing the direction which rotation is
+ // applied.
+ if (sensorRotation == Surface.ROTATION_90) {
+ sensorRotation = Surface.ROTATION_270;
+ } else if (sensorRotation == Surface.ROTATION_270) {
+ sensorRotation = Surface.ROTATION_90;
+ }
+ }
mLastSensorRotation = sensorRotation;
if (sensorRotation < 0) {
sensorRotation = lastRotation;
@@ -1573,7 +1590,7 @@
proto.end(token);
}
- boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
+ boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
if (mFoldController == null) return false;
return mFoldController.isDeviceInPosture(state, isTabletop);
}
@@ -1585,10 +1602,10 @@
/**
* Called by the DeviceStateManager callback when the device state changes.
*/
- void foldStateChanged(DeviceStateController.FoldState foldState) {
+ void foldStateChanged(DeviceStateController.DeviceState deviceState) {
if (mFoldController != null) {
synchronized (mLock) {
- mFoldController.foldStateChanged(foldState);
+ mFoldController.foldStateChanged(deviceState);
}
}
}
@@ -1596,8 +1613,8 @@
private class FoldController {
@Surface.Rotation
private int mHalfFoldSavedRotation = -1; // No saved rotation
- private DeviceStateController.FoldState mFoldState =
- DeviceStateController.FoldState.UNKNOWN;
+ private DeviceStateController.DeviceState mDeviceState =
+ DeviceStateController.DeviceState.UNKNOWN;
private boolean mInHalfFoldTransition = false;
private final boolean mIsDisplayAlwaysSeparatingHinge;
private final Set<Integer> mTabletopRotations;
@@ -1637,32 +1654,33 @@
R.bool.config_isDisplayHingeAlwaysSeparating);
}
- boolean isDeviceInPosture(DeviceStateController.FoldState state, boolean isTabletop) {
- if (state != mFoldState) {
+ boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) {
+ if (state != mDeviceState) {
return false;
}
- if (mFoldState == DeviceStateController.FoldState.HALF_FOLDED) {
+ if (mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) {
return !(isTabletop ^ mTabletopRotations.contains(mRotation));
}
return true;
}
- DeviceStateController.FoldState getFoldState() {
- return mFoldState;
+ DeviceStateController.DeviceState getFoldState() {
+ return mDeviceState;
}
boolean isSeparatingHinge() {
- return mFoldState == DeviceStateController.FoldState.HALF_FOLDED
- || (mFoldState == DeviceStateController.FoldState.OPEN
+ return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED
+ || (mDeviceState == DeviceStateController.DeviceState.OPEN
&& mIsDisplayAlwaysSeparatingHinge);
}
boolean overrideFrozenRotation() {
- return mFoldState == DeviceStateController.FoldState.HALF_FOLDED;
+ return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED;
}
boolean shouldRevertOverriddenRotation() {
- return mFoldState == DeviceStateController.FoldState.OPEN // When transitioning to open.
+ // When transitioning to open.
+ return mDeviceState == DeviceStateController.DeviceState.OPEN
&& mInHalfFoldTransition
&& mHalfFoldSavedRotation != -1 // Ignore if we've already reverted.
&& mUserRotationMode
@@ -1676,30 +1694,30 @@
return savedRotation;
}
- void foldStateChanged(DeviceStateController.FoldState newState) {
+ void foldStateChanged(DeviceStateController.DeviceState newState) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
"foldStateChanged: displayId %d, halfFoldStateChanged %s, "
+ "saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, "
+ "mLastOrientation: %d, mRotation: %d",
mDisplayContent.getDisplayId(), newState.name(), mHalfFoldSavedRotation,
mUserRotation, mLastSensorRotation, mLastOrientation, mRotation);
- if (mFoldState == DeviceStateController.FoldState.UNKNOWN) {
- mFoldState = newState;
+ if (mDeviceState == DeviceStateController.DeviceState.UNKNOWN) {
+ mDeviceState = newState;
return;
}
- if (newState == DeviceStateController.FoldState.HALF_FOLDED
- && mFoldState != DeviceStateController.FoldState.HALF_FOLDED) {
+ if (newState == DeviceStateController.DeviceState.HALF_FOLDED
+ && mDeviceState != DeviceStateController.DeviceState.HALF_FOLDED) {
// The device has transitioned to HALF_FOLDED state: save the current rotation and
// update the device rotation.
mHalfFoldSavedRotation = mRotation;
- mFoldState = newState;
+ mDeviceState = newState;
// Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will
// return true, so rotation is unlocked.
mService.updateRotation(false /* alwaysSendConfiguration */,
false /* forceRelayout */);
} else {
mInHalfFoldTransition = true;
- mFoldState = newState;
+ mDeviceState = newState;
// Tell the device to update its orientation.
mService.updateRotation(false /* alwaysSendConfiguration */,
false /* forceRelayout */);
@@ -1719,8 +1737,9 @@
private class OrientationListener extends WindowOrientationListener implements Runnable {
transient boolean mEnabled;
- OrientationListener(Context context, Handler handler) {
- super(context, handler);
+ OrientationListener(Context context, Handler handler,
+ @Surface.Rotation int defaultRotation) {
+ super(context, handler, defaultRotation);
}
@Override
@@ -1822,7 +1841,7 @@
final long mTimestamp = System.currentTimeMillis();
final int mHalfFoldSavedRotation;
final boolean mInHalfFoldTransition;
- final DeviceStateController.FoldState mFoldState;
+ final DeviceStateController.DeviceState mDeviceState;
@Nullable final String mDisplayRotationCompatPolicySummary;
Record(DisplayRotation dr, int fromRotation, int toRotation) {
@@ -1843,8 +1862,9 @@
if (source != null) {
mLastOrientationSource = source.toString();
final WindowState w = source.asWindowState();
- mSourceOrientation =
- w != null ? w.mAttrs.screenOrientation : source.mOrientation;
+ mSourceOrientation = w != null
+ ? w.mAttrs.screenOrientation
+ : source.getOverrideOrientation();
} else {
mLastOrientationSource = null;
mSourceOrientation = SCREEN_ORIENTATION_UNSET;
@@ -1852,11 +1872,11 @@
if (dr.mFoldController != null) {
mHalfFoldSavedRotation = dr.mFoldController.mHalfFoldSavedRotation;
mInHalfFoldTransition = dr.mFoldController.mInHalfFoldTransition;
- mFoldState = dr.mFoldController.mFoldState;
+ mDeviceState = dr.mFoldController.mDeviceState;
} else {
mHalfFoldSavedRotation = NO_FOLD_CONTROLLER;
mInHalfFoldTransition = false;
- mFoldState = DeviceStateController.FoldState.UNKNOWN;
+ mDeviceState = DeviceStateController.DeviceState.UNKNOWN;
}
mDisplayRotationCompatPolicySummary = dc.mDisplayRotationCompatPolicy == null
? null
@@ -1882,7 +1902,7 @@
pw.println(prefix + " halfFoldSavedRotation="
+ mHalfFoldSavedRotation
+ " mInHalfFoldTransition=" + mInHalfFoldTransition
- + " mFoldState=" + mFoldState);
+ + " mFoldState=" + mDeviceState);
}
if (mDisplayRotationCompatPolicySummary != null) {
pw.println(prefix + mDisplayRotationCompatPolicySummary);
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index c6037da..3ffb2fa 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -296,8 +296,8 @@
&& activity.getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED
// "locked" and "nosensor" values are often used by camera apps that can't
// handle dynamic changes so we shouldn't force rotate them.
- && activity.getRequestedOrientation() != SCREEN_ORIENTATION_NOSENSOR
- && activity.getRequestedOrientation() != SCREEN_ORIENTATION_LOCKED
+ && activity.getOverrideOrientation() != SCREEN_ORIENTATION_NOSENSOR
+ && activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED
&& mCameraIdPackageBiMap.containsPackageName(activity.packageName)
&& activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 73d1ff9d..c5a50ca 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -17,11 +17,21 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
+import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ActivityInfo.isFixedOrientation;
+import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.screenOrientationToString;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -29,6 +39,8 @@
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;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM;
@@ -62,6 +74,9 @@
import static com.android.server.wm.LetterboxConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.LetterboxConfiguration.letterboxBackgroundTypeToString;
+import static java.lang.Boolean.FALSE;
+import static java.lang.Boolean.TRUE;
+
import android.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
import android.content.pm.ActivityInfo.ScreenOrientation;
@@ -111,6 +126,34 @@
*/
private final float mExpandedTaskBarHeight;
+ // TODO(b/265576778): Cache other overrides as well.
+
+ // Corresponds to OVERRIDE_ANY_ORIENTATION
+ private final boolean mIsOverrideAnyOrientationEnabled;
+ // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
+ private final boolean mIsOverrideToPortraitOrientationEnabled;
+ // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR
+ private final boolean mIsOverrideToNosensorOrientationEnabled;
+ // Corresponds to OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE
+ private final boolean mIsOverrideToReverseLandscapeOrientationEnabled;
+ // Corresponds to OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION
+ private final boolean mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled;
+
+ // Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION
+ private final boolean mIsOverrideCameraCompatDisableForceRotationEnabled;
+ // Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH
+ private final boolean mIsOverrideCameraCompatDisableRefreshEnabled;
+ // Corresponds to OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE
+ private final boolean mIsOverrideCameraCompatEnableRefreshViaPauseEnabled;
+
+ // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
+ private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
+
+ @Nullable
+ private final Boolean mBooleanPropertyAllowOrientationOverride;
+ @Nullable
+ private final Boolean mBooleanPropertyAllowDisplayOrientationOverride;
+
/*
* WindowContainerListener responsible to make translucent activities inherit
* constraints from the first opaque activity beneath them. It's null for not
@@ -193,6 +236,35 @@
mExpandedTaskBarHeight =
getResources().getDimensionPixelSize(R.dimen.taskbar_frame_height);
+
+ mBooleanPropertyAllowOrientationOverride =
+ readComponentProperty(packageManager, mActivityRecord.packageName,
+ /* gatingCondition */ null,
+ PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
+ mBooleanPropertyAllowDisplayOrientationOverride =
+ readComponentProperty(packageManager, mActivityRecord.packageName,
+ /* gatingCondition */ null,
+ PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE);
+
+ mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION);
+ mIsOverrideToPortraitOrientationEnabled =
+ isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT);
+ mIsOverrideToReverseLandscapeOrientationEnabled =
+ isCompatChangeEnabled(OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE);
+ mIsOverrideToNosensorOrientationEnabled =
+ isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR);
+ mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled =
+ isCompatChangeEnabled(OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION);
+
+ mIsOverrideCameraCompatDisableForceRotationEnabled =
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION);
+ mIsOverrideCameraCompatDisableRefreshEnabled =
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH);
+ mIsOverrideCameraCompatEnableRefreshViaPauseEnabled =
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+
+ mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
+ isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
}
/**
@@ -207,8 +279,8 @@
*/
@Nullable
private static Boolean readComponentProperty(PackageManager packageManager, String packageName,
- BooleanSupplier gatingCondition, String propertyName) {
- if (!gatingCondition.getAsBoolean()) {
+ @Nullable BooleanSupplier gatingCondition, String propertyName) {
+ if (gatingCondition != null && !gatingCondition.getAsBoolean()) {
return null;
}
try {
@@ -262,7 +334,7 @@
if (!shouldEnableWithOverrideAndProperty(
/* gatingCondition */ mLetterboxConfiguration
::isPolicyForIgnoringRequestedOrientationEnabled,
- OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION,
+ mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
mBooleanPropertyIgnoreRequestedOrientation)) {
return false;
}
@@ -308,6 +380,66 @@
}
/**
+ * Whether should fix display orientation to landscape natural orientation when a task is
+ * fullscreen and the display is ignoring orientation requests.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Opt-in per-app override is enabled
+ * <li>Task is in fullscreen.
+ * <li>{@link DisplayContent#getIgnoreOrientationRequest} is enabled
+ * <li>Natural orientation of the display is landscape.
+ * </ul>
+ */
+ boolean shouldUseDisplayLandscapeNaturalOrientation() {
+ return shouldEnableWithOptInOverrideAndOptOutProperty(
+ /* gatingCondition */ () -> mActivityRecord.mDisplayContent != null
+ && mActivityRecord.getTask() != null
+ && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest()
+ && !mActivityRecord.getTask().inMultiWindowMode()
+ && mActivityRecord.mDisplayContent.getNaturalOrientation()
+ == ORIENTATION_LANDSCAPE,
+ mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled,
+ mBooleanPropertyAllowDisplayOrientationOverride);
+ }
+
+ @ScreenOrientation
+ int overrideOrientationIfNeeded(@ScreenOrientation int candidate) {
+ if (FALSE.equals(mBooleanPropertyAllowOrientationOverride)) {
+ return candidate;
+ }
+
+ if (mIsOverrideToReverseLandscapeOrientationEnabled
+ && (isFixedOrientationLandscape(candidate) || mIsOverrideAnyOrientationEnabled)) {
+ Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
+ + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_REVERSE_LANDSCAPE));
+ return SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+ }
+
+ if (!mIsOverrideAnyOrientationEnabled && isFixedOrientation(candidate)) {
+ return candidate;
+ }
+
+ if (mIsOverrideToPortraitOrientationEnabled) {
+ Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
+ + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_PORTRAIT));
+ return SCREEN_ORIENTATION_PORTRAIT;
+ }
+
+ if (mIsOverrideToNosensorOrientationEnabled) {
+ Slog.w(TAG, "Requested orientation " + screenOrientationToString(candidate) + " for "
+ + mActivityRecord + " is overridden to "
+ + screenOrientationToString(SCREEN_ORIENTATION_NOSENSOR));
+ return SCREEN_ORIENTATION_NOSENSOR;
+ }
+
+ return candidate;
+ }
+
+ /**
* Whether activity is eligible for activity "refresh" after camera compat force rotation
* treatment. See {@link DisplayRotationCompatPolicy} for context.
*
@@ -322,7 +454,7 @@
return shouldEnableWithOptOutOverrideAndProperty(
/* gatingCondition */ () -> mLetterboxConfiguration
.isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
- OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH,
+ mIsOverrideCameraCompatDisableRefreshEnabled,
mBooleanPropertyCameraCompatAllowRefresh);
}
@@ -344,7 +476,7 @@
return shouldEnableWithOverrideAndProperty(
/* gatingCondition */ () -> mLetterboxConfiguration
.isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
- OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
+ mIsOverrideCameraCompatEnableRefreshViaPauseEnabled,
mBooleanPropertyCameraCompatEnableRefreshViaPause);
}
@@ -363,15 +495,19 @@
return shouldEnableWithOptOutOverrideAndProperty(
/* gatingCondition */ () -> mLetterboxConfiguration
.isCameraCompatTreatmentEnabled(/* checkDeviceConfig */ true),
- OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION,
+ mIsOverrideCameraCompatDisableForceRotationEnabled,
mBooleanPropertyCameraCompatAllowForceRotation);
}
+ private boolean isCompatChangeEnabled(long overrideChangeId) {
+ return mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
/**
* Returns {@code true} when the following conditions are met:
* <ul>
* <li>{@code gatingCondition} isn't {@code false}
- * <li>OEM didn't opt out with a {@code overrideChangeId} override
+ * <li>OEM didn't opt out with a per-app override
* <li>App developers didn't opt out with a component {@code property}
* </ul>
*
@@ -379,12 +515,30 @@
* disabled on per-app basis by OEMs or app developers.
*/
private boolean shouldEnableWithOptOutOverrideAndProperty(BooleanSupplier gatingCondition,
- long overrideChangeId, Boolean property) {
+ boolean isOverrideChangeEnabled, Boolean property) {
if (!gatingCondition.getAsBoolean()) {
return false;
}
- return !Boolean.FALSE.equals(property)
- && !mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ return !FALSE.equals(property) && !isOverrideChangeEnabled;
+ }
+
+ /**
+ * Returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>{@code gatingCondition} isn't {@code false}
+ * <li>OEM did opt in with a per-app override
+ * <li>App developers didn't opt out with a component {@code property}
+ * </ul>
+ *
+ * <p>This is used for the treatments that are enabled based with the heuristic but can be
+ * disabled on per-app basis by OEMs or app developers.
+ */
+ private boolean shouldEnableWithOptInOverrideAndOptOutProperty(BooleanSupplier gatingCondition,
+ boolean isOverrideChangeEnabled, Boolean property) {
+ if (!gatingCondition.getAsBoolean()) {
+ return false;
+ }
+ return !FALSE.equals(property) && isOverrideChangeEnabled;
}
/**
@@ -393,21 +547,20 @@
* <li>{@code gatingCondition} isn't {@code false}
* <li>App developers didn't opt out with a component {@code property}
* <li>App developers opted in with a component {@code property} or an OEM opted in with a
- * component {@code property}
+ * per-app override
* </ul>
*
* <p>This is used for the treatments that are enabled only on per-app basis.
*/
private boolean shouldEnableWithOverrideAndProperty(BooleanSupplier gatingCondition,
- long overrideChangeId, Boolean property) {
+ boolean isOverrideChangeEnabled, Boolean property) {
if (!gatingCondition.getAsBoolean()) {
return false;
}
- if (Boolean.FALSE.equals(property)) {
+ if (FALSE.equals(property)) {
return false;
}
- return Boolean.TRUE.equals(property)
- || mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ return TRUE.equals(property) || isOverrideChangeEnabled;
}
boolean hasWallpaperBackgroundForLetterbox() {
@@ -542,7 +695,7 @@
// Note that we check the task rather than the parent as with ActivityEmbedding the parent might
// be a TaskFragment, and its windowing mode is always MULTI_WINDOW, even if the task is
// actually fullscreen.
- private boolean isDisplayFullScreenAndInPosture(DeviceStateController.FoldState state,
+ private boolean isDisplayFullScreenAndInPosture(DeviceStateController.DeviceState state,
boolean isTabletop) {
Task task = mActivityRecord.getTask();
return mActivityRecord.mDisplayContent != null
@@ -568,7 +721,7 @@
// Don't check resolved configuration because it may not be updated yet during
// configuration change.
boolean bookMode = isDisplayFullScreenAndInPosture(
- DeviceStateController.FoldState.HALF_FOLDED, false /* isTabletop */);
+ DeviceStateController.DeviceState.HALF_FOLDED, false /* isTabletop */);
return isHorizontalReachabilityEnabled(parentConfiguration)
// Using the last global dynamic position to avoid "jumps" when moving
// between apps or activities.
@@ -580,7 +733,7 @@
// Don't check resolved configuration because it may not be updated yet during
// configuration change.
boolean tabletopMode = isDisplayFullScreenAndInPosture(
- DeviceStateController.FoldState.HALF_FOLDED, true /* isTabletop */);
+ DeviceStateController.DeviceState.HALF_FOLDED, true /* isTabletop */);
return isVerticalReachabilityEnabled(parentConfiguration)
// Using the last global dynamic position to avoid "jumps" when moving
// between apps or activities.
@@ -1107,7 +1260,7 @@
int letterboxPositionForHorizontalReachability = getLetterboxConfiguration()
.getLetterboxPositionForHorizontalReachability(
isDisplayFullScreenAndInPosture(
- DeviceStateController.FoldState.HALF_FOLDED,
+ DeviceStateController.DeviceState.HALF_FOLDED,
false /* isTabletop */));
positionToLog = letterboxHorizontalReachabilityPositionToLetterboxPosition(
letterboxPositionForHorizontalReachability);
@@ -1115,7 +1268,7 @@
int letterboxPositionForVerticalReachability = getLetterboxConfiguration()
.getLetterboxPositionForVerticalReachability(
isDisplayFullScreenAndInPosture(
- DeviceStateController.FoldState.HALF_FOLDED,
+ DeviceStateController.DeviceState.HALF_FOLDED,
true /* isTabletop */));
positionToLog = letterboxVerticalReachabilityPositionToLetterboxPosition(
letterboxPositionForVerticalReachability);
@@ -1224,7 +1377,8 @@
// To avoid wrong behaviour, we're not forcing orientation for activities with not
// fixed orientation (e.g. permission dialogs).
return hasInheritedLetterboxBehavior()
- && mActivityRecord.mOrientation != SCREEN_ORIENTATION_UNSPECIFIED;
+ && mActivityRecord.getOverrideOrientation()
+ != SCREEN_ORIENTATION_UNSPECIFIED;
}
float getInheritedMinAspectRatio() {
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 30bdc34..2edb082 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -51,10 +51,10 @@
/**
* Called by the DeviceStateManager callback when the state changes.
*/
- void foldStateChanged(DeviceStateController.FoldState newFoldState) {
+ void foldStateChanged(DeviceStateController.DeviceState newDeviceState) {
// Ignore transitions to/from half-folded.
- if (newFoldState == DeviceStateController.FoldState.HALF_FOLDED) return;
- mIsFolded = newFoldState == DeviceStateController.FoldState.FOLDED;
+ if (newDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) return;
+ mIsFolded = newDeviceState == DeviceStateController.DeviceState.FOLDED;
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 8bdab9c..9a20354 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -73,6 +73,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.pm.ActivityInfo.ScreenOrientation;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.Point;
@@ -178,8 +179,9 @@
protected final WindowList<E> mChildren = new WindowList<E>();
// The specified orientation for this window container.
- @ActivityInfo.ScreenOrientation
- protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ // Shouldn't be accessed directly since subclasses can override getOverrideOrientation.
+ @ScreenOrientation
+ private int mOverrideOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
/**
* The window container which decides its orientation since the last time
@@ -1427,19 +1429,20 @@
/**
* Gets the configuration orientation by the requested screen orientation
- * ({@link ActivityInfo.ScreenOrientation}) of this activity.
+ * ({@link ScreenOrientation}) of this activity.
*
* @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE},
* {@link Configuration#ORIENTATION_PORTRAIT},
* {@link Configuration#ORIENTATION_UNDEFINED}).
*/
+ @ScreenOrientation
int getRequestedConfigurationOrientation() {
return getRequestedConfigurationOrientation(false /* forDisplay */);
}
/**
* Gets the configuration orientation by the requested screen orientation
- * ({@link ActivityInfo.ScreenOrientation}) of this activity.
+ * ({@link ScreenOrientation}) of this activity.
*
* @param forDisplay whether it is the requested config orientation for display.
* If {@code true}, we may reverse the requested orientation if the root is
@@ -1450,8 +1453,9 @@
* {@link Configuration#ORIENTATION_PORTRAIT},
* {@link Configuration#ORIENTATION_UNDEFINED}).
*/
+ @ScreenOrientation
int getRequestedConfigurationOrientation(boolean forDisplay) {
- int requestedOrientation = mOrientation;
+ int requestedOrientation = getOverrideOrientation();
final RootDisplayArea root = getRootDisplayArea();
if (forDisplay && root != null && root.isOrientationDifferentFromDisplay()) {
// Reverse the requested orientation if the orientation of its root is different from
@@ -1461,7 +1465,7 @@
// (portrait).
// When an app below the DAG is requesting landscape, it should actually request the
// display to be portrait, so that the DAG and the app will be in landscape.
- requestedOrientation = reverseOrientation(mOrientation);
+ requestedOrientation = reverseOrientation(getOverrideOrientation());
}
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
@@ -1486,7 +1490,7 @@
*
* @param orientation the specified orientation.
*/
- void setOrientation(int orientation) {
+ void setOrientation(@ScreenOrientation int orientation) {
setOrientation(orientation, null /* requestingContainer */);
}
@@ -1494,17 +1498,17 @@
* Sets the specified orientation of this container. It percolates this change upward along the
* hierarchy to let each level of the hierarchy a chance to respond to it.
*
- * @param orientation the specified orientation. Needs to be one of {@link
- * android.content.pm.ActivityInfo.ScreenOrientation}.
+ * @param orientation the specified orientation. Needs to be one of {@link ScreenOrientation}.
* @param requestingContainer the container which orientation request has changed. Mostly used
* to ensure it gets correct configuration.
*/
- void setOrientation(int orientation, @Nullable WindowContainer requestingContainer) {
- if (mOrientation == orientation) {
+ void setOrientation(@ScreenOrientation int orientation,
+ @Nullable WindowContainer requestingContainer) {
+ if (getOverrideOrientation() == orientation) {
return;
}
- mOrientation = orientation;
+ setOverrideOrientation(orientation);
final WindowContainer parent = getParent();
if (parent != null) {
if (getConfiguration().orientation != getRequestedConfigurationOrientation()
@@ -1523,9 +1527,9 @@
}
}
- @ActivityInfo.ScreenOrientation
+ @ScreenOrientation
int getOrientation() {
- return getOrientation(mOrientation);
+ return getOrientation(getOverrideOrientation());
}
/**
@@ -1539,7 +1543,8 @@
* better match.
* @return The orientation as specified by this branch or the window hierarchy.
*/
- int getOrientation(int candidate) {
+ @ScreenOrientation
+ int getOrientation(@ScreenOrientation int candidate) {
mLastOrientationSource = null;
if (!providesOrientation()) {
return SCREEN_ORIENTATION_UNSET;
@@ -1549,16 +1554,16 @@
// specified; otherwise we prefer to use the orientation of its topmost child that has one
// specified and fall back on this container's unset or unspecified value as a candidate
// if none of the children have a better candidate for the orientation.
- if (mOrientation != SCREEN_ORIENTATION_UNSET
- && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ if (getOverrideOrientation() != SCREEN_ORIENTATION_UNSET
+ && getOverrideOrientation() != SCREEN_ORIENTATION_UNSPECIFIED) {
mLastOrientationSource = this;
- return mOrientation;
+ return getOverrideOrientation();
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
- // TODO: Maybe mOrientation should default to SCREEN_ORIENTATION_UNSET vs.
+ // TODO: Maybe mOverrideOrientation should default to SCREEN_ORIENTATION_UNSET vs.
// SCREEN_ORIENTATION_UNSPECIFIED?
final int orientation = wc.getOrientation(candidate == SCREEN_ORIENTATION_BEHIND
? SCREEN_ORIENTATION_BEHIND : SCREEN_ORIENTATION_UNSET);
@@ -1590,6 +1595,20 @@
}
/**
+ * Returns orientation specified on this level of hierarchy without taking children into
+ * account, like {@link #getOrientation} does, allowing subclasses to override. See {@link
+ * ActivityRecord#getOverrideOrientation} for an example.
+ */
+ @ScreenOrientation
+ protected int getOverrideOrientation() {
+ return mOverrideOrientation;
+ }
+
+ protected void setOverrideOrientation(@ScreenOrientation int orientation) {
+ mOverrideOrientation = orientation;
+ }
+
+ /**
* @return The deepest source which decides the orientation of this window container since the
* last time {@link #getOrientation(int) was called.
*/
@@ -2635,7 +2654,7 @@
final long token = proto.start(fieldId);
super.dumpDebug(proto, CONFIGURATION_CONTAINER, logLevel);
- proto.write(ORIENTATION, mOrientation);
+ proto.write(ORIENTATION, mOverrideOrientation);
proto.write(VISIBLE, isVisible);
writeIdentifierToProto(proto, IDENTIFIER);
if (mSurfaceAnimator.isAnimating()) {
diff --git a/services/core/java/com/android/server/wm/WindowOrientationListener.java b/services/core/java/com/android/server/wm/WindowOrientationListener.java
index 3e165e4..14c816d 100644
--- a/services/core/java/com/android/server/wm/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/wm/WindowOrientationListener.java
@@ -88,14 +88,19 @@
private final Object mLock = new Object();
+ @Surface.Rotation
+ private final int mDefaultRotation;
+
/**
* Creates a new WindowOrientationListener.
*
* @param context for the WindowOrientationListener.
* @param handler Provides the Looper for receiving sensor updates.
+ * @param defaultRotation Default rotation of the display.
*/
- public WindowOrientationListener(Context context, Handler handler) {
- this(context, handler, SensorManager.SENSOR_DELAY_UI);
+ public WindowOrientationListener(Context context, Handler handler,
+ @Surface.Rotation int defaultRotation) {
+ this(context, handler, defaultRotation, SensorManager.SENSOR_DELAY_UI);
}
/**
@@ -103,7 +108,7 @@
*
* @param context for the WindowOrientationListener.
* @param handler Provides the Looper for receiving sensor updates.
- * @param wmService WindowManagerService to read the device config from.
+ * @param defaultRotation Default rotation of the display.
* @param rate at which sensor events are processed (see also
* {@link android.hardware.SensorManager SensorManager}). Use the default
* value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
@@ -111,10 +116,11 @@
*
* This constructor is private since no one uses it.
*/
- private WindowOrientationListener(
- Context context, Handler handler, int rate) {
+ private WindowOrientationListener(Context context, Handler handler,
+ @Surface.Rotation int defaultRotation, int rate) {
mContext = context;
mHandler = handler;
+ mDefaultRotation = defaultRotation;
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);
@@ -1159,7 +1165,7 @@
"Reusing the last rotation resolution: " + mLastRotationResolution);
finalizeRotation(mLastRotationResolution);
} else {
- finalizeRotation(Surface.ROTATION_0);
+ finalizeRotation(mDefaultRotation);
}
return;
}
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 33ac735..ea0481e 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -43,6 +43,9 @@
<!-- needed by TrustManagerServiceTest to access LockSettings' secure storage -->
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
+ <!-- needed by GameManagerServiceTest because GameManager creates a UidObserver -->
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
+
<application android:testOnly="true"
android:debuggable="true">
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index fa4a9de..2d5f0b0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -29,13 +29,16 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.app.ActivityManager;
import android.app.GameManager;
import android.app.GameModeInfo;
import android.app.GameState;
@@ -203,6 +206,23 @@
LocalServices.addService(PowerManagerInternal.class, mMockPowerManager);
}
+ private void mockAppCategory(String packageName, @ApplicationInfo.Category int category)
+ throws Exception {
+ reset(mMockPackageManager);
+ final ApplicationInfo gameApplicationInfo = new ApplicationInfo();
+ gameApplicationInfo.category = category;
+ gameApplicationInfo.packageName = packageName;
+ final PackageInfo pi = new PackageInfo();
+ pi.packageName = packageName;
+ pi.applicationInfo = gameApplicationInfo;
+ final List<PackageInfo> packages = new ArrayList<>();
+ packages.add(pi);
+ when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), anyInt()))
+ .thenReturn(packages);
+ when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(gameApplicationInfo);
+ }
+
@After
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(PowerManagerInternal.class);
@@ -1597,4 +1617,113 @@
ArgumentMatchers.eq(DEFAULT_PACKAGE_UID),
ArgumentMatchers.eq(0.0f));
}
+
+ private GameManagerService createServiceAndStartUser(int userId) {
+ GameManagerService gameManagerService = new GameManagerService(mMockContext,
+ mTestLooper.getLooper());
+ startUser(gameManagerService, userId);
+ return gameManagerService;
+ }
+
+ @Test
+ public void testGamePowerMode_gamePackage() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, true);
+ }
+
+ @Test
+ public void testGamePowerMode_twoGames() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages1 = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages1);
+ String someGamePkg = "some.game";
+ String[] packages2 = {someGamePkg};
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+ HashMap<Integer, Boolean> powerState = new HashMap<>();
+ doAnswer(inv -> powerState.put(inv.getArgument(0), inv.getArgument(1)))
+ .when(mMockPowerManager).setPowerMode(anyInt(), anyBoolean());
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ assertTrue(powerState.get(Mode.GAME));
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ assertTrue(powerState.get(Mode.GAME));
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ assertFalse(powerState.get(Mode.GAME));
+ }
+
+ @Test
+ public void testGamePowerMode_twoGamesOverlap() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages1 = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages1);
+ String someGamePkg = "some.game";
+ String[] packages2 = {someGamePkg};
+ int somePackageId = DEFAULT_PACKAGE_UID + 1;
+ when(mMockPackageManager.getPackagesForUid(somePackageId)).thenReturn(packages2);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ somePackageId, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, true);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, false);
+ }
+
+ @Test
+ public void testGamePowerMode_released() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {mPackageName};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME, false);
+ }
+
+ @Test
+ public void testGamePowerMode_noPackage() throws Exception {
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, true);
+ }
+
+ @Test
+ public void testGamePowerMode_notAGamePackage() throws Exception {
+ mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_IMAGE);
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {"someapp"};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, true);
+ }
+
+ @Test
+ public void testGamePowerMode_notAGamePackageNotReleased() throws Exception {
+ mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_IMAGE);
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ String[] packages = {"someapp"};
+ when(mMockPackageManager.getPackagesForUid(DEFAULT_PACKAGE_UID)).thenReturn(packages);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 0, 0);
+ gameManagerService.mUidObserver.onUidStateChanged(
+ DEFAULT_PACKAGE_UID, ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND, 0, 0);
+ verify(mMockPowerManager, times(0)).setPowerMode(Mode.GAME, false);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
index 3de65c1..1b3a199 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowOrientationListenerTest.java
@@ -132,6 +132,19 @@
assertThat(mFinalizedRotation).isEqualTo(DEFAULT_SENSOR_ROTATION);
}
+ @Test
+ public void testOnSensorChanged_screenLocked_doNotCallRotationResolverReturnDefaultRotation() {
+ mWindowOrientationListener = new TestableWindowOrientationListener(mMockContext,
+ mHandler, /* defaultRotation */ Surface.ROTATION_180);
+ mWindowOrientationListener.mRotationResolverService = mFakeRotationResolverInternal;
+ mWindowOrientationListener.mIsScreenLocked = true;
+
+ mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
+
+ assertThat(mWindowOrientationListener.mIsOnProposedRotationChangedCalled).isFalse();
+ assertThat(mFinalizedRotation).isEqualTo(Surface.ROTATION_180);
+ }
+
static final class TestableRotationResolver extends RotationResolverInternal {
@Surface.Rotation
RotationResolverCallbackInternal mCallback;
@@ -166,21 +179,17 @@
}
}
- @Test
- public void testOnSensorChanged_inLockScreen_doNotCallRotationResolver() {
- mWindowOrientationListener.mIsScreenLocked = true;
-
- mWindowOrientationListener.mOrientationJudge.onSensorChanged(mFakeSensorEvent);
-
- assertThat(mWindowOrientationListener.mIsOnProposedRotationChangedCalled).isFalse();
- }
-
final class TestableWindowOrientationListener extends WindowOrientationListener {
private boolean mIsOnProposedRotationChangedCalled = false;
private boolean mIsScreenLocked;
TestableWindowOrientationListener(Context context, Handler handler) {
- super(context, handler);
+ this(context, handler, Surface.ROTATION_0);
+ }
+
+ TestableWindowOrientationListener(Context context, Handler handler,
+ @Surface.Rotation int defaultRotation) {
+ super(context, handler, defaultRotation);
this.mOrientationJudge = new OrientationSensorJudge();
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 7986043..8b1384e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1582,6 +1582,55 @@
}
@Test
+ public void testSetComponentState_differentUsers() throws Exception {
+ Context context = mock(Context.class);
+ PackageManager pm = mock(PackageManager.class);
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ when(context.getPackageName()).thenReturn(mContext.getPackageName());
+ when(context.getUserId()).thenReturn(mContext.getUserId());
+ when(context.getPackageManager()).thenReturn(pm);
+ when(pm.getApplicationInfo(anyString(), anyInt())).thenReturn(ai);
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles, mIpm,
+ APPROVAL_BY_COMPONENT);
+ ComponentName cn = ComponentName.unflattenFromString("a/a");
+
+ addExpectedServices(service, Arrays.asList("a"), mZero.id);
+ addExpectedServices(service, Arrays.asList("a"), mTen.id);
+ when(context.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ ServiceConnection sc = (ServiceConnection) args[1];
+ sc.onServiceConnected(cn, mock(IBinder.class));
+ return true;
+ });
+ service.addApprovedList("a/a", 0, true);
+ service.addApprovedList("a/a", 10, false);
+
+ service.registerService(cn, mZero.id);
+ assertTrue(service.isBound(cn, mZero.id));
+
+ service.onUserSwitched(mTen.id);
+ assertFalse(service.isBound(cn, mZero.id));
+ service.registerService(cn, mTen.id);
+ assertTrue(service.isBound(cn, mTen.id));
+
+ service.setComponentState(cn, mTen.id, false);
+ assertFalse(service.isBound(cn, mZero.id));
+ assertFalse(service.isBound(cn, mTen.id));
+
+ // Service should be rebound on user 0, since it was only disabled for user 10.
+ service.onUserSwitched(mZero.id);
+ assertTrue(service.isBound(cn, mZero.id));
+ assertFalse(service.isBound(cn, mTen.id));
+
+ // Service should stay unbound on going back to user 10.
+ service.onUserSwitched(mTen.id);
+ assertFalse(service.isBound(cn, mZero.id));
+ assertFalse(service.isBound(cn, mTen.id));
+ }
+ @Test
public void testOnPackagesChanged_nullValuesPassed_noNullPointers() {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
ManagedServices service = new TestManagedServices(getContext(), mLock, mUserProfiles,
@@ -1847,7 +1896,7 @@
}
private void addExpectedServices(final ManagedServices service, final List<String> packages,
- int userId) {
+ int userId) throws Exception {
ManagedServices.Config config = service.getConfig();
when(mPm.queryIntentServicesAsUser(any(), anyInt(), eq(userId))).
thenAnswer(new Answer<List<ResolveInfo>>() {
@@ -1876,6 +1925,20 @@
return new ArrayList<>();
}
});
+
+ when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
+ (Answer<ServiceInfo>) invocation -> {
+ ComponentName invocationCn = invocation.getArgument(0);
+ if (invocationCn != null && packages.contains(invocationCn.getPackageName())) {
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = invocationCn.getPackageName();
+ serviceInfo.name = invocationCn.getClassName();
+ serviceInfo.permission = service.getConfig().bindPermission;
+ return serviceInfo;
+ }
+ return null;
+ }
+ );
}
private List<String> stringToList(String list) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
index 86732c9..2a28ae2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DeviceStateControllerTests.java
@@ -16,13 +16,12 @@
package com.android.server.wm;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import android.content.Context;
import android.content.res.Resources;
@@ -32,9 +31,10 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.R;
+
import org.junit.Before;
import org.junit.Test;
-import org.mockito.ArgumentCaptor;
import java.util.function.Consumer;
@@ -48,92 +48,76 @@
@Presubmit
public class DeviceStateControllerTests {
- private DeviceStateController.FoldStateListener mFoldStateListener;
private DeviceStateController mTarget;
private DeviceStateControllerBuilder mBuilder;
private Context mMockContext;
- private Handler mMockHandler;
- private Resources mMockRes;
private DeviceStateManager mMockDeviceStateManager;
-
- private Consumer<DeviceStateController.FoldState> mDelegate;
- private DeviceStateController.FoldState mCurrentState = DeviceStateController.FoldState.UNKNOWN;
+ private DeviceStateController.DeviceState mCurrentState =
+ DeviceStateController.DeviceState.UNKNOWN;
@Before
public void setUp() {
mBuilder = new DeviceStateControllerBuilder();
- mCurrentState = DeviceStateController.FoldState.UNKNOWN;
+ mCurrentState = DeviceStateController.DeviceState.UNKNOWN;
}
- private void initialize(boolean supportFold, boolean supportHalfFold) throws Exception {
+ private void initialize(boolean supportFold, boolean supportHalfFold) {
mBuilder.setSupportFold(supportFold, supportHalfFold);
- mDelegate = (newFoldState) -> {
+ Consumer<DeviceStateController.DeviceState> delegate = (newFoldState) -> {
mCurrentState = newFoldState;
};
- mBuilder.setDelegate(mDelegate);
+ mBuilder.setDelegate(delegate);
mBuilder.build();
- verifyFoldStateListenerRegistration(1);
+ verify(mMockDeviceStateManager).registerCallback(any(), any());
}
@Test
- public void testInitialization() throws Exception {
+ public void testInitialization() {
initialize(true /* supportFold */, true /* supportHalfFolded */);
- mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
- assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
+ mTarget.onStateChanged(mOpenDeviceStates[0]);
+ assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
}
@Test
- public void testInitializationWithNoFoldSupport() throws Exception {
+ public void testInitializationWithNoFoldSupport() {
initialize(false /* supportFold */, false /* supportHalfFolded */);
- mFoldStateListener.onStateChanged(mFoldedStates[0]);
+ mTarget.onStateChanged(mFoldedStates[0]);
// Note that the folded state is ignored.
- assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
+ assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState);
}
@Test
- public void testWithFoldSupported() throws Exception {
+ public void testWithFoldSupported() {
initialize(true /* supportFold */, false /* supportHalfFolded */);
- mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
- assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
- mFoldStateListener.onStateChanged(mFoldedStates[0]);
- assertEquals(mCurrentState, DeviceStateController.FoldState.FOLDED);
- mFoldStateListener.onStateChanged(mHalfFoldedStates[0]);
- assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN); // Ignored
+ mTarget.onStateChanged(mOpenDeviceStates[0]);
+ assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+ mTarget.onStateChanged(mFoldedStates[0]);
+ assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+ mTarget.onStateChanged(mHalfFoldedStates[0]);
+ assertEquals(DeviceStateController.DeviceState.UNKNOWN, mCurrentState); // Ignored
}
@Test
- public void testWithHalfFoldSupported() throws Exception {
+ public void testWithHalfFoldSupported() {
initialize(true /* supportFold */, true /* supportHalfFolded */);
- mFoldStateListener.onStateChanged(mUnfoldedStates[0]);
- assertEquals(mCurrentState, DeviceStateController.FoldState.OPEN);
- mFoldStateListener.onStateChanged(mFoldedStates[0]);
- assertEquals(mCurrentState, DeviceStateController.FoldState.FOLDED);
- mFoldStateListener.onStateChanged(mHalfFoldedStates[0]);
- assertEquals(mCurrentState, DeviceStateController.FoldState.HALF_FOLDED);
+ mTarget.onStateChanged(mOpenDeviceStates[0]);
+ assertEquals(DeviceStateController.DeviceState.OPEN, mCurrentState);
+ mTarget.onStateChanged(mFoldedStates[0]);
+ assertEquals(DeviceStateController.DeviceState.FOLDED, mCurrentState);
+ mTarget.onStateChanged(mHalfFoldedStates[0]);
+ assertEquals(DeviceStateController.DeviceState.HALF_FOLDED, mCurrentState);
}
-
private final int[] mFoldedStates = {0};
- private final int[] mUnfoldedStates = {1};
+ private final int[] mOpenDeviceStates = {1};
private final int[] mHalfFoldedStates = {2};
-
-
- private void verifyFoldStateListenerRegistration(int numOfInvocation) {
- final ArgumentCaptor<DeviceStateController.FoldStateListener> listenerCaptor =
- ArgumentCaptor.forClass(DeviceStateController.FoldStateListener.class);
- verify(mMockDeviceStateManager, times(numOfInvocation)).registerCallback(
- any(),
- listenerCaptor.capture());
- if (numOfInvocation > 0) {
- mFoldStateListener = listenerCaptor.getValue();
- }
- }
+ private final int[] mRearDisplayStates = {3};
private class DeviceStateControllerBuilder {
private boolean mSupportFold = false;
private boolean mSupportHalfFold = false;
- private Consumer<DeviceStateController.FoldState> mDelegate;
+ private Consumer<DeviceStateController.DeviceState> mDelegate;
DeviceStateControllerBuilder setSupportFold(
boolean supportFold, boolean supportHalfFold) {
@@ -143,34 +127,44 @@
}
DeviceStateControllerBuilder setDelegate(
- Consumer<DeviceStateController.FoldState> delegate) {
+ Consumer<DeviceStateController.DeviceState> delegate) {
mDelegate = delegate;
return this;
}
private void mockFold(boolean enableFold, boolean enableHalfFold) {
+ if (enableFold || enableHalfFold) {
+ when(mMockContext.getResources()
+ .getIntArray(R.array.config_openDeviceStates))
+ .thenReturn(mOpenDeviceStates);
+ when(mMockContext.getResources()
+ .getIntArray(R.array.config_rearDisplayDeviceStates))
+ .thenReturn(mRearDisplayStates);
+ }
+
if (enableFold) {
- when(mMockContext.getResources().getIntArray(
- com.android.internal.R.array.config_foldedDeviceStates))
+ when(mMockContext.getResources()
+ .getIntArray(R.array.config_foldedDeviceStates))
.thenReturn(mFoldedStates);
}
if (enableHalfFold) {
- when(mMockContext.getResources().getIntArray(
- com.android.internal.R.array.config_halfFoldedDeviceStates))
+ when(mMockContext.getResources()
+ .getIntArray(R.array.config_halfFoldedDeviceStates))
.thenReturn(mHalfFoldedStates);
}
}
- private void build() throws Exception {
+ private void build() {
mMockContext = mock(Context.class);
- mMockRes = mock(Resources.class);
- when(mMockContext.getResources()).thenReturn((mMockRes));
mMockDeviceStateManager = mock(DeviceStateManager.class);
when(mMockContext.getSystemService(DeviceStateManager.class))
.thenReturn(mMockDeviceStateManager);
+ Resources mockRes = mock(Resources.class);
+ when(mMockContext.getResources()).thenReturn((mockRes));
mockFold(mSupportFold, mSupportHalfFold);
- mMockHandler = mock(Handler.class);
- mTarget = new DeviceStateController(mMockContext, mMockHandler, mDelegate);
+ Handler mockHandler = mock(Handler.class);
+ mTarget = new DeviceStateController(mMockContext, mockHandler);
+ mTarget.registerDeviceStateCallback(mDelegate);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index b0639bf..dc12469 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1736,7 +1736,7 @@
// No need to apply rotation if the display ignores orientation request.
doCallRealMethod().when(displayContent).rotationForActivityInDifferentOrientation(any());
- pinnedActivity.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
+ pinnedActivity.setOverrideOrientation(SCREEN_ORIENTATION_LANDSCAPE);
displayContent.setIgnoreOrientationRequest(true);
assertEquals(WindowConfiguration.ROTATION_UNDEFINED,
displayContent.rotationForActivityInDifferentOrientation(pinnedActivity));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 4ce43e1..ed2b0a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -56,6 +56,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.os.PowerManagerInternal;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -111,6 +112,7 @@
private ContentResolver mMockResolver;
private FakeSettingsProvider mFakeSettingsProvider;
private StatusBarManagerInternal mMockStatusBarManagerInternal;
+ private DeviceStateManager mMockDeviceStateManager;
// Fields below are callbacks captured from test target.
private ContentObserver mShowRotationSuggestionsObserver;
@@ -120,6 +122,7 @@
private DisplayRotationBuilder mBuilder;
+ private DeviceStateController mDeviceStateController;
private DisplayRotation mTarget;
@BeforeClass
@@ -484,6 +487,34 @@
SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
}
+ @Test
+ public void testReverseRotation() throws Exception {
+ mBuilder.build();
+ configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
+
+ when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis()).thenReturn(true);
+
+ thawRotation();
+
+ enableOrientationSensor();
+
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
+ assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
+ SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_270));
+ assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
+ SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
+ assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
+ SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
+
+ mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
+ assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
+ SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_180));
+ }
+
private boolean waitForUiHandler() {
final CountDownLatch latch = new CountDownLatch(1);
UiThread.getHandler().post(latch::countDown);
@@ -705,7 +736,7 @@
enableOrientationSensor();
- mTarget.foldStateChanged(DeviceStateController.FoldState.OPEN);
+ mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
freezeRotation(Surface.ROTATION_270);
mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
@@ -715,7 +746,7 @@
SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
// ... until half-fold
- mTarget.foldStateChanged(DeviceStateController.FoldState.HALF_FOLDED);
+ mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
assertTrue(waitForUiHandler());
verify(sMockWm).updateRotation(false, false);
assertTrue(waitForUiHandler());
@@ -723,7 +754,7 @@
SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
// ... then transition back to flat
- mTarget.foldStateChanged(DeviceStateController.FoldState.OPEN);
+ mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
assertTrue(waitForUiHandler());
verify(sMockWm, atLeast(1)).updateRotation(false, false);
assertTrue(waitForUiHandler());
@@ -1097,8 +1128,14 @@
mMockDisplayWindowSettings = mock(DisplayWindowSettings.class);
+ mMockDeviceStateManager = mock(DeviceStateManager.class);
+ when(mMockContext.getSystemService(eq(DeviceStateManager.class)))
+ .thenReturn(mMockDeviceStateManager);
+
+ mDeviceStateController = mock(DeviceStateController.class);
mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayAddress,
- mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext, new Object()) {
+ mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext, new Object(),
+ mDeviceStateController) {
@Override
DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy(
WindowManagerService service, DisplayContent displayContent) {
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 478bd85..c7f19fb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -16,14 +16,27 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
+import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
+import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
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.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;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -89,6 +102,7 @@
public TestRule compatChangeRule = new PlatformCompatChangeRule();
private ActivityRecord mActivity;
+ private Task mTask;
private DisplayContent mDisplayContent;
private LetterboxUiController mController;
private LetterboxConfiguration mLetterboxConfiguration;
@@ -488,6 +502,130 @@
return mainWindow;
}
+ // overrideOrientationIfNeeded
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
+ public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsPortrait()
+ throws Exception {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
+ public void testOverrideOrientationIfNeeded_portraitOverrideEnabled_returnsNosensor() {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_NOSENSOR);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR})
+ public void testOverrideOrientationIfNeeded_nosensorOverride_orientationFixed_returnsUnchanged() {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
+ public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationPortraitOrUndefined_returnsUnchanged() {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_PORTRAIT);
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE})
+ public void testOverrideOrientationIfNeeded_reverseLandscapeOverride_orientationLandscape_returnsReverseLandscape() {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_LANDSCAPE),
+ SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
+ public void testOverrideOrientationIfNeeded_portraitOverride_orientationFixed_returnsUnchanged() {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_NOSENSOR);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT, OVERRIDE_ANY_ORIENTATION})
+ public void testOverrideOrientationIfNeeded_portraitAndIgnoreFixedOverrides_returnsPortrait() {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_NOSENSOR), SCREEN_ORIENTATION_PORTRAIT);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR, OVERRIDE_ANY_ORIENTATION})
+ public void testOverrideOrientationIfNeeded_noSensorAndIgnoreFixedOverrides_returnsNosensor() {
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_PORTRAIT), SCREEN_ORIENTATION_NOSENSOR);
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT})
+ public void testOverrideOrientationIfNeeded_propertyIsFalse_returnsUnchanged()
+ throws Exception {
+ mockThatProperty(PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE, /* value */ false);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ assertEquals(mController.overrideOrientationIfNeeded(
+ /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
+ }
+
+ // shouldUseDisplayLandscapeNaturalOrientation
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+ public void testShouldUseDisplayLandscapeNaturalOrientation_override_returnsTrue() {
+ prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+ assertTrue(mController.shouldUseDisplayLandscapeNaturalOrientation());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+ public void testShouldUseDisplayLandscapeNaturalOrientation_overrideAndFalseProperty_returnsFalse()
+ throws Exception {
+ mockThatProperty(PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE, /* value */ false);
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+ assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+ public void testShouldUseDisplayLandscapeNaturalOrientation_portraitNaturalOrientation_returnsFalse() {
+ prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+ doReturn(ORIENTATION_PORTRAIT).when(mDisplayContent).getNaturalOrientation();
+
+ assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+ public void testShouldUseDisplayLandscapeNaturalOrientation_disabledIgnoreOrientationRequest_returnsFalse() {
+ prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+ mDisplayContent.setIgnoreOrientationRequest(false);
+
+ assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION})
+ public void testShouldUseDisplayLandscapeNaturalOrientation_inMultiWindowMode_returnsFalse() {
+ prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation();
+
+ spyOn(mTask);
+ doReturn(true).when(mTask).inMultiWindowMode();
+
+ assertFalse(mController.shouldUseDisplayLandscapeNaturalOrientation());
+ }
+
private void mockThatProperty(String propertyName, boolean value) throws Exception {
Property property = new Property(propertyName, /* value */ value, /* packageName */ "",
/* className */ "");
@@ -496,6 +634,12 @@
doReturn(property).when(pm).getProperty(eq(propertyName), anyString());
}
+ private void prepareActivityThatShouldUseDisplayLandscapeNaturalOrientation() {
+ spyOn(mDisplayContent);
+ doReturn(ORIENTATION_LANDSCAPE).when(mDisplayContent).getNaturalOrientation();
+ mDisplayContent.setIgnoreOrientationRequest(true);
+ }
+
private void prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch() {
doReturn(true).when(mLetterboxConfiguration)
.isPolicyForIgnoringRequestedOrientationEnabled();
@@ -505,10 +649,10 @@
private ActivityRecord setUpActivityWithComponent() {
mDisplayContent = new TestDisplayContent
.Builder(mAtm, /* dw */ 1000, /* dh */ 2000).build();
- Task task = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
+ mTask = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent).build();
final ActivityRecord activity = new ActivityBuilder(mAtm)
.setOnTop(true)
- .setTask(task)
+ .setTask(mTask)
// Set the component to be that of the test class in order to enable compat changes
.setComponent(ComponentName.createRelative(mContext,
com.android.server.wm.LetterboxUiControllerTest.class.getName()))
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 4808474..06e3854 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -468,7 +468,7 @@
mWm.setRecentsAnimationController(mController);
spyOn(mDisplayContent.mFixedRotationTransitionListener);
final ActivityRecord recents = mock(ActivityRecord.class);
- recents.mOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+ recents.setOverrideOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
doReturn(ORIENTATION_PORTRAIT).when(recents)
.getRequestedConfigurationOrientation(anyBoolean());
mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recents);
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 46d69d1..c9ff150 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -98,7 +98,7 @@
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.wm.DeviceStateController.FoldState;
+import com.android.server.wm.DeviceStateController.DeviceState;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -3055,6 +3055,20 @@
}
@Test
+ public void testApplyAspectRatio_containingRatioAlmostEqualToMaxRatio_boundsUnchanged() {
+ setUpDisplaySizeWithApp(1981, 2576);
+ mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f);
+
+ final Rect originalBounds = new Rect(mActivity.getBounds());
+ prepareUnresizable(mActivity, 1.3f, SCREEN_ORIENTATION_UNSPECIFIED);
+
+ // The containing aspect ratio is now 1.3003534, while the desired aspect ratio is 1.3. The
+ // bounds of the activity should not be changed as the difference is too small
+ assertEquals(mActivity.getBounds(), originalBounds);
+ }
+
+ @Test
public void testUpdateResolvedBoundsHorizontalPosition_activityFillParentWidth() {
// When activity width equals parent width, multiplier shouldn't have any effect.
assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity(
@@ -3186,9 +3200,9 @@
private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) {
final DisplayRotation r = mActivity.mDisplayContent.getDisplayRotation();
doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge();
- doReturn(false).when(r).isDeviceInPosture(any(FoldState.class), anyBoolean());
+ doReturn(false).when(r).isDeviceInPosture(any(DeviceState.class), anyBoolean());
if (isHalfFolded) {
- doReturn(true).when(r).isDeviceInPosture(FoldState.HALF_FOLDED, isTabletop);
+ doReturn(true).when(r).isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop);
}
mActivity.recomputeConfiguration();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index ed7d123..2446fc4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1557,7 +1557,7 @@
@Override
int getOrientation() {
- return getOrientation(super.mOrientation);
+ return getOrientation(super.getOverrideOrientation());
}
@Override
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 42a5af7..17c354a 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -36,6 +36,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
/**
@@ -106,6 +107,12 @@
return false;
}
+ /**
+ * List of connected MIDI devices
+ */
+ private final HashMap<String, UsbMidiDevice>
+ mMidiDevices = new HashMap<String, UsbMidiDevice>();
+
// UsbMidiDevice for USB peripheral mode (gadget) device
private UsbMidiDevice mPeripheralMidiDevice = null;
@@ -249,6 +256,8 @@
}
}
+ addMidiDevice(deviceAddress, usbDevice, parser, cardRec);
+
logDevices("deviceAdded()");
if (DEBUG) {
@@ -256,6 +265,54 @@
}
}
+ private void addMidiDevice(String deviceAddress, UsbDevice usbDevice,
+ UsbDescriptorParser parser, AlsaCardsParser.AlsaCardRecord cardRec) {
+ boolean hasMidi = parser.hasMIDIInterface();
+ // UsbHostManager will create UsbDirectMidiDevices instead if MIDI 2 is supported.
+ boolean hasMidi2 = parser.containsUniversalMidiDeviceEndpoint();
+ if (DEBUG) {
+ Slog.d(TAG, "hasMidi: " + hasMidi + " mHasMidiFeature:" + mHasMidiFeature);
+ Slog.d(TAG, "hasMidi2: " + hasMidi2);
+ }
+ if (mHasMidiFeature && hasMidi && !hasMidi2) {
+ Bundle properties = new Bundle();
+ String manufacturer = usbDevice.getManufacturerName();
+ String product = usbDevice.getProductName();
+ String version = usbDevice.getVersion();
+ String name;
+ if (manufacturer == null || manufacturer.isEmpty()) {
+ name = product;
+ } else if (product == null || product.isEmpty()) {
+ name = manufacturer;
+ } else {
+ name = manufacturer + " " + product;
+ }
+ properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
+ properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
+ properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
+ properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
+ properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
+ usbDevice.getSerialNumber());
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, cardRec.getCardNum());
+ properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, 0 /*deviceNum*/);
+ properties.putParcelable(MidiDeviceInfo.PROPERTY_USB_DEVICE, usbDevice);
+
+ int numLegacyMidiInputs = parser.calculateNumLegacyMidiInputs();
+ int numLegacyMidiOutputs = parser.calculateNumLegacyMidiOutputs();
+ if (DEBUG) {
+ Slog.d(TAG, "numLegacyMidiInputs: " + numLegacyMidiInputs);
+ Slog.d(TAG, "numLegacyMidiOutputs:" + numLegacyMidiOutputs);
+ }
+
+ UsbMidiDevice usbMidiDevice = UsbMidiDevice.create(mContext, properties,
+ cardRec.getCardNum(), 0 /*device*/, numLegacyMidiInputs,
+ numLegacyMidiOutputs);
+ if (usbMidiDevice != null) {
+ mMidiDevices.put(deviceAddress, usbMidiDevice);
+ }
+ }
+ }
+
/* package */ synchronized void usbDeviceRemoved(String deviceAddress/*UsbDevice usbDevice*/) {
if (DEBUG) {
Slog.d(TAG, "deviceRemoved(" + deviceAddress + ")");
@@ -269,6 +326,13 @@
selectDefaultDevice(); // if there any external devices left, select one of them
}
+ // MIDI
+ UsbMidiDevice usbMidiDevice = mMidiDevices.remove(deviceAddress);
+ if (usbMidiDevice != null) {
+ Slog.i(TAG, "USB MIDI Device Removed: " + deviceAddress);
+ IoUtils.closeQuietly(usbMidiDevice);
+ }
+
logDevices("usbDeviceRemoved()");
}
@@ -324,6 +388,12 @@
usbAlsaDevice.dump(dump, "alsa_devices", UsbAlsaManagerProto.ALSA_DEVICES);
}
+ for (String deviceAddr : mMidiDevices.keySet()) {
+ // A UsbMidiDevice does not have a handle to the UsbDevice anymore
+ mMidiDevices.get(deviceAddr).dump(deviceAddr, dump, "midi_devices",
+ UsbAlsaManagerProto.MIDI_DEVICES);
+ }
+
dump.end(token);
}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index f389276..b3eb285 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -444,14 +444,19 @@
} else {
Slog.e(TAG, "Universal Midi Device is null.");
}
- }
- if (parser.containsLegacyMidiDeviceEndpoint()) {
- UsbDirectMidiDevice midiDevice = UsbDirectMidiDevice.create(mContext,
- newDevice, parser, false, uniqueUsbDeviceIdentifier);
- if (midiDevice != null) {
- midiDevices.add(midiDevice);
- } else {
- Slog.e(TAG, "Legacy Midi Device is null.");
+
+ // Use UsbDirectMidiDevice only if this supports MIDI 2.0 as well.
+ // ALSA removes the audio sound card if MIDI interfaces are removed.
+ // This means that as long as ALSA is used for audio, MIDI 1.0 USB
+ // devices should use the ALSA path for MIDI.
+ if (parser.containsLegacyMidiDeviceEndpoint()) {
+ midiDevice = UsbDirectMidiDevice.create(mContext,
+ newDevice, parser, false, uniqueUsbDeviceIdentifier);
+ if (midiDevice != null) {
+ midiDevices.add(midiDevice);
+ } else {
+ Slog.e(TAG, "Legacy Midi Device is null.");
+ }
}
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 3f2d8c8..c6ea228 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -79,6 +79,10 @@
mInterfaceDescriptors.add(interfaceDesc);
}
+ ArrayList<UsbInterfaceDescriptor> getInterfaceDescriptors() {
+ return mInterfaceDescriptors;
+ }
+
private boolean isAudioInterface(UsbInterfaceDescriptor descriptor) {
return descriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO
&& descriptor.getUsbSubclass() == UsbDescriptor.AUDIO_AUDIOSTREAMING;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index cd6ea68..626ce89 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -40,6 +40,7 @@
private UsbDeviceDescriptor mDeviceDescriptor;
private UsbConfigDescriptor mCurConfigDescriptor;
private UsbInterfaceDescriptor mCurInterfaceDescriptor;
+ private UsbEndpointDescriptor mCurEndpointDescriptor;
// The AudioClass spec implemented by the AudioClass Interfaces
// This may well be different than the overall USB Spec.
@@ -165,7 +166,7 @@
break;
case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
- descriptor = new UsbEndpointDescriptor(length, type);
+ descriptor = mCurEndpointDescriptor = new UsbEndpointDescriptor(length, type);
if (mCurInterfaceDescriptor != null) {
mCurInterfaceDescriptor.addEndpointDescriptor(
(UsbEndpointDescriptor) descriptor);
@@ -265,6 +266,9 @@
+ Integer.toHexString(subClass));
break;
}
+ if (mCurEndpointDescriptor != null && descriptor != null) {
+ mCurEndpointDescriptor.setClassSpecificEndpointDescriptor(descriptor);
+ }
}
break;
@@ -798,6 +802,84 @@
/**
* @hide
*/
+ private int calculateNumLegacyMidiPorts(boolean isOutput) {
+ // Only look at the first config.
+ UsbConfigDescriptor configDescriptor = null;
+ for (UsbDescriptor descriptor : mDescriptors) {
+ if (descriptor.getType() == UsbDescriptor.DESCRIPTORTYPE_CONFIG) {
+ if (descriptor instanceof UsbConfigDescriptor) {
+ configDescriptor = (UsbConfigDescriptor) descriptor;
+ break;
+ } else {
+ Log.w(TAG, "Unrecognized Config l: " + descriptor.getLength()
+ + " t:0x" + Integer.toHexString(descriptor.getType()));
+ }
+ }
+ }
+ if (configDescriptor == null) {
+ Log.w(TAG, "Config not found");
+ return 0;
+ }
+
+ ArrayList<UsbInterfaceDescriptor> legacyMidiInterfaceDescriptors =
+ new ArrayList<UsbInterfaceDescriptor>();
+ for (UsbInterfaceDescriptor interfaceDescriptor
+ : configDescriptor.getInterfaceDescriptors()) {
+ if (interfaceDescriptor.getUsbClass() == UsbDescriptor.CLASSID_AUDIO) {
+ if (interfaceDescriptor.getUsbSubclass() == UsbDescriptor.AUDIO_MIDISTREAMING) {
+ UsbDescriptor midiHeaderDescriptor =
+ interfaceDescriptor.getMidiHeaderInterfaceDescriptor();
+ if (midiHeaderDescriptor != null) {
+ if (midiHeaderDescriptor instanceof UsbMSMidiHeader) {
+ UsbMSMidiHeader midiHeader =
+ (UsbMSMidiHeader) midiHeaderDescriptor;
+ if (midiHeader.getMidiStreamingClass() == MS_MIDI_1_0) {
+ legacyMidiInterfaceDescriptors.add(interfaceDescriptor);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ int count = 0;
+ for (UsbInterfaceDescriptor interfaceDescriptor : legacyMidiInterfaceDescriptors) {
+ for (int i = 0; i < interfaceDescriptor.getNumEndpoints(); i++) {
+ UsbEndpointDescriptor endpoint =
+ interfaceDescriptor.getEndpointDescriptor(i);
+ // 0 is output, 1 << 7 is input.
+ if ((endpoint.getDirection() == 0) == isOutput) {
+ UsbDescriptor classSpecificEndpointDescriptor =
+ endpoint.getClassSpecificEndpointDescriptor();
+ if (classSpecificEndpointDescriptor != null
+ && (classSpecificEndpointDescriptor instanceof UsbACMidi10Endpoint)) {
+ UsbACMidi10Endpoint midiEndpoint =
+ (UsbACMidi10Endpoint) classSpecificEndpointDescriptor;
+ count += midiEndpoint.getNumJacks();
+ }
+ }
+ }
+ }
+ return count;
+ }
+
+ /**
+ * @hide
+ */
+ public int calculateNumLegacyMidiInputs() {
+ return calculateNumLegacyMidiPorts(false /*isOutput*/);
+ }
+
+ /**
+ * @hide
+ */
+ public int calculateNumLegacyMidiOutputs() {
+ return calculateNumLegacyMidiPorts(true /*isOutput*/);
+ }
+
+ /**
+ * @hide
+ */
public float getInputHeadsetProbability() {
if (hasMIDIInterface()) {
return 0.0f;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
index ab07ce7..1f448ac 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -79,6 +79,8 @@
private byte mRefresh;
private byte mSyncAddress;
+ private UsbDescriptor mClassSpecificEndpointDescriptor;
+
public UsbEndpointDescriptor(int length, byte type) {
super(length, type);
mHierarchyLevel = 4;
@@ -112,6 +114,14 @@
return mEndpointAddress & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION;
}
+ void setClassSpecificEndpointDescriptor(UsbDescriptor descriptor) {
+ mClassSpecificEndpointDescriptor = descriptor;
+ }
+
+ UsbDescriptor getClassSpecificEndpointDescriptor() {
+ return mClassSpecificEndpointDescriptor;
+ }
+
/**
* Returns a UsbEndpoint that this UsbEndpointDescriptor is describing.
*/