Merge "Destroy prefetched layers when the context is destroyed" into main
diff --git a/Android.bp b/Android.bp
index 040bb6e..93d6f53 100644
--- a/Android.bp
+++ b/Android.bp
@@ -212,7 +212,7 @@
"android.hardware.contexthub-V1.0-java",
"android.hardware.contexthub-V1.1-java",
"android.hardware.contexthub-V1.2-java",
- "android.hardware.contexthub-V2-java",
+ "android.hardware.contexthub-V3-java",
"android.hardware.gnss-V1.0-java",
"android.hardware.gnss-V2.1-java",
"android.hardware.health-V1.0-java-constants",
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 863efff..c18b7ef 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -196,9 +196,6 @@
return 1;
}
- void const* mapbase = MAP_FAILED;
- ssize_t mapsize = -1;
-
void* base = NULL;
// setThreadPoolMaxThreadCount(0) actually tells the kernel it's
@@ -278,9 +275,6 @@
}
}
close(fd);
- if (mapbase != MAP_FAILED) {
- munmap((void *)mapbase, mapsize);
- }
return 0;
}
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index 39248730..7489ce3 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -8,6 +8,7 @@
import android.app.UiAutomationConnection;
import android.content.Intent;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.RemoteException;
/**
@@ -26,6 +27,10 @@
throw new IllegalStateException("Already connected!");
}
mHandlerThread.start();
+ // The AccessibilityInteractionClient used by UiAutomation expects the main looper to
+ // be prepared. In most contexts this is normally done automatically, but must be called
+ // explicitly here because this is a shell tool.
+ Looper.prepareMainLooper();
mUiAutomation = new UiAutomation(mHandlerThread.getLooper(),
new UiAutomationConnection());
mUiAutomation.connect();
diff --git a/core/api/current.txt b/core/api/current.txt
index c2bc5a2..d03122d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -14271,6 +14271,7 @@
method public android.database.sqlite.SQLiteStatement compileStatement(String) throws android.database.SQLException;
method @NonNull public static android.database.sqlite.SQLiteDatabase create(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
method @NonNull public static android.database.sqlite.SQLiteDatabase createInMemory(@NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
+ method @NonNull public android.database.sqlite.SQLiteRawStatement createRawStatement(@NonNull String);
method public int delete(String, String, String[]);
method public static boolean deleteDatabase(@NonNull java.io.File);
method public void disableWriteAheadLogging();
@@ -14281,6 +14282,7 @@
method public void execSQL(String, Object[]) throws android.database.SQLException;
method public static String findEditTable(String);
method public java.util.List<android.util.Pair<java.lang.String,java.lang.String>> getAttachedDbs();
+ method public long getLastInsertRowId();
method public long getMaximumSize();
method public long getPageSize();
method public String getPath();
@@ -14506,6 +14508,39 @@
method public int update(@NonNull android.database.sqlite.SQLiteDatabase, @NonNull android.content.ContentValues, @Nullable String, @Nullable String[]);
}
+ public final class SQLiteRawStatement implements java.io.Closeable {
+ method public void bindBlob(int, @NonNull byte[]) throws android.database.sqlite.SQLiteException;
+ method public void bindBlob(int, @NonNull byte[], int, int) throws android.database.sqlite.SQLiteException;
+ method public void bindDouble(int, double) throws android.database.sqlite.SQLiteException;
+ method public void bindInt(int, int) throws android.database.sqlite.SQLiteException;
+ method public void bindLong(int, long) throws android.database.sqlite.SQLiteException;
+ method public void bindNull(int) throws android.database.sqlite.SQLiteException;
+ method public void bindText(int, @NonNull String) throws android.database.sqlite.SQLiteException;
+ method public void clearBindings();
+ method public void close();
+ method @Nullable public byte[] getColumnBlob(int) throws android.database.sqlite.SQLiteException;
+ method public double getColumnDouble(int) throws android.database.sqlite.SQLiteException;
+ method public int getColumnInt(int) throws android.database.sqlite.SQLiteException;
+ method public int getColumnLength(int) throws android.database.sqlite.SQLiteException;
+ method public long getColumnLong(int) throws android.database.sqlite.SQLiteException;
+ method @NonNull public String getColumnName(int) throws android.database.sqlite.SQLiteException;
+ method @NonNull public String getColumnText(int) throws android.database.sqlite.SQLiteException;
+ method public int getColumnType(int) throws android.database.sqlite.SQLiteException;
+ method public int getParameterCount();
+ method public int getParameterIndex(@NonNull String);
+ method @Nullable public String getParameterName(int);
+ method public int getResultColumnCount();
+ method public boolean isOpen();
+ method public int readColumnBlob(int, @NonNull byte[], int, int, int) throws android.database.sqlite.SQLiteException;
+ method public void reset();
+ method public boolean step() throws android.database.sqlite.SQLiteException;
+ field public static final int SQLITE_DATA_TYPE_BLOB = 4; // 0x4
+ field public static final int SQLITE_DATA_TYPE_FLOAT = 2; // 0x2
+ field public static final int SQLITE_DATA_TYPE_INTEGER = 1; // 0x1
+ field public static final int SQLITE_DATA_TYPE_NULL = 5; // 0x5
+ field public static final int SQLITE_DATA_TYPE_TEXT = 3; // 0x3
+ }
+
public class SQLiteReadOnlyDatabaseException extends android.database.sqlite.SQLiteException {
ctor public SQLiteReadOnlyDatabaseException();
ctor public SQLiteReadOnlyDatabaseException(String);
@@ -44870,6 +44905,7 @@
method public boolean isNetworkRegistered();
method public boolean isNetworkRoaming();
method public boolean isNetworkSearching();
+ method public boolean isNonTerrestrialNetwork();
method @Deprecated public boolean isRegistered();
method @Deprecated public boolean isRoaming();
method @Deprecated public boolean isSearching();
@@ -45099,6 +45135,7 @@
method public boolean getRoaming();
method public int getState();
method public boolean isSearching();
+ method public boolean isUsingNonTerrestrialNetwork();
method public void setIsManualSelection(boolean);
method public void setOperatorName(String, String, String);
method public void setRoaming(boolean);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cf24f20..b22884f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -455,6 +455,7 @@
field public static final int config_defaultCallScreening = 17039398; // 0x1040026
field public static final int config_defaultDialer = 17039395; // 0x1040023
field public static final int config_defaultNotes = 17039429; // 0x1040045
+ field public static final int config_defaultRetailDemo;
field public static final int config_defaultSms = 17039396; // 0x1040024
field public static final int config_devicePolicyManagement = 17039421; // 0x104003d
field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
@@ -11676,6 +11677,8 @@
public static final class Settings.System extends android.provider.Settings.NameValueTable {
method @RequiresPermission(android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, boolean, boolean);
+ method public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String);
}
public static final class SimPhonebookContract.SimRecords {
@@ -14207,6 +14210,7 @@
method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int);
method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setIsNonTerrestrialNetwork(boolean);
method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegisteredPlmn(@Nullable String);
method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int);
method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 8ac507c..b4a6955 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1346,8 +1346,26 @@
}
// Set the child animators to the right end:
if (mShouldResetValuesAtStart) {
- initChildren();
- skipToEndValue(!mReversing);
+ if (isInitialized()) {
+ skipToEndValue(!mReversing);
+ } else if (mReversing) {
+ // Reversing but haven't initialized all the children yet.
+ initChildren();
+ skipToEndValue(!mReversing);
+ } else {
+ // If not all children are initialized and play direction is forward
+ for (int i = mEvents.size() - 1; i >= 0; i--) {
+ if (mEvents.get(i).mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) {
+ Animator anim = mEvents.get(i).mNode.mAnimation;
+ // Only reset the animations that have been initialized to start value,
+ // so that if they are defined without a start value, they will get the
+ // values set at the right time (i.e. the next animation run)
+ if (anim.isInitialized()) {
+ anim.skipToEndValue(true);
+ }
+ }
+ }
+ }
}
if (mReversing || mStartDelay == 0 || mSeekState.isActive()) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 02aeac7..a5acf03 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2268,9 +2268,9 @@
*
* <p>An activity can never receive a new intent in the resumed state. You can count on
* {@link #onResume} being called after this method, though not necessarily immediately after
- * the completion this callback. If the activity was resumed, it will be paused and new intent
- * will be delivered, followed by {@link #onResume}. If the activity wasn't in the resumed
- * state, then new intent can be delivered immediately, with {@link #onResume()} called
+ * the completion of this callback. If the activity was resumed, it will be paused and new
+ * intent will be delivered, followed by {@link #onResume}. If the activity wasn't in the
+ * resumed state, then new intent can be delivered immediately, with {@link #onResume()} called
* sometime later when activity becomes active again.
*
* <p>Note that {@link #getIntent} still returns the original Intent. You
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 397acf8..853528f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4248,21 +4248,22 @@
decorView.addView(view);
view.requestLayout();
- view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
+ view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
private boolean mHandled = false;
@Override
- public void onDraw() {
+ public boolean onPreDraw() {
if (mHandled) {
- return;
+ return true;
}
mHandled = true;
// Transfer the splash screen view from shell to client.
- // Call syncTransferSplashscreenViewTransaction at the first onDraw so we can ensure
- // the client view is ready to show and we can use applyTransactionOnDraw to make
- // all transitions happen at the same frame.
+ // Call syncTransferSplashscreenViewTransaction at the first onPreDraw, so we can
+ // ensure the client view is ready to show, and can use applyTransactionOnDraw to
+ // make all transitions happen at the same frame.
syncTransferSplashscreenViewTransaction(
view, r.token, decorView, startingWindowLeash);
- view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
+ view.post(() -> view.getViewTreeObserver().removeOnPreDrawListener(this));
+ return true;
}
});
}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index f467200..e447dc5 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -61,6 +61,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.PasswordValidationError;
import com.android.internal.widget.VerifyCredentialResponse;
import java.nio.charset.Charset;
@@ -885,12 +886,8 @@
}
Objects.requireNonNull(password, "Password cannot be null.");
complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
- // TODO: b/131755827 add devicePolicyManager support for Auto
- DevicePolicyManager devicePolicyManager =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
PasswordMetrics adminMetrics =
- devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
-
+ mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) {
return PasswordMetrics.validateCredential(adminMetrics, complexity,
credential).size() == 0;
@@ -913,11 +910,8 @@
return -1;
}
complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
- // TODO: b/131755827 add devicePolicyManager support for Auto
- DevicePolicyManager devicePolicyManager =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
PasswordMetrics adminMetrics =
- devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
+ mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
PasswordMetrics minMetrics =
PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity);
return minMetrics.length;
@@ -1139,6 +1133,14 @@
currentLockType, currentPassword);
LockscreenCredential newCredential = createLockscreenCredential(
newLockType, newPassword);
+ PasswordMetrics adminMetrics =
+ mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
+ List<PasswordValidationError> errors = PasswordMetrics.validateCredential(adminMetrics,
+ DevicePolicyManager.PASSWORD_COMPLEXITY_NONE, newCredential);
+ if (!errors.isEmpty()) {
+ Log.e(TAG, "New credential is not valid: " + errors.get(0));
+ return false;
+ }
return mLockPatternUtils.setLockCredential(newCredential, currentCredential, userId);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e7c92ee..892b45e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2171,6 +2171,10 @@
}
}
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ visitIconUri(visitor, getIcon());
+ }
+
@Override
public Action clone() {
return new Action(
@@ -2858,7 +2862,7 @@
if (actions != null) {
for (Action action : actions) {
- visitIconUri(visitor, action.getIcon());
+ action.visitUris(visitor);
}
}
@@ -2939,6 +2943,11 @@
if (mBubbleMetadata != null) {
visitIconUri(visitor, mBubbleMetadata.getIcon());
}
+
+ if (extras != null && extras.containsKey(WearableExtender.EXTRA_WEARABLE_EXTENSIONS)) {
+ WearableExtender extender = new WearableExtender(this);
+ extender.visitUris(visitor);
+ }
}
/**
@@ -3038,10 +3047,9 @@
// cannot look into the extras as there may be parcelables there that
// the platform does not know how to handle. To go around that we have
// an explicit list of the pending intents in the extras bundle.
- final boolean collectPendingIntents = (allPendingIntents == null);
- if (collectPendingIntents) {
- PendingIntent.setOnMarshaledListener(
- (PendingIntent intent, Parcel out, int outFlags) -> {
+ PendingIntent.OnMarshaledListener addedListener = null;
+ if (allPendingIntents == null) {
+ addedListener = (PendingIntent intent, Parcel out, int outFlags) -> {
if (parcel == out) {
synchronized (this) {
if (allPendingIntents == null) {
@@ -3050,7 +3058,8 @@
allPendingIntents.add(intent);
}
}
- });
+ };
+ PendingIntent.addOnMarshaledListener(addedListener);
}
try {
// IMPORTANT: Add marshaling code in writeToParcelImpl as we
@@ -3061,8 +3070,8 @@
parcel.writeArraySet(allPendingIntents);
}
} finally {
- if (collectPendingIntents) {
- PendingIntent.setOnMarshaledListener(null);
+ if (addedListener != null) {
+ PendingIntent.removeOnMarshaledListener(addedListener);
}
}
}
@@ -3468,8 +3477,11 @@
*
* @hide
*/
- public void setAllowlistToken(@Nullable IBinder token) {
- mAllowlistToken = token;
+ public void clearAllowlistToken() {
+ mAllowlistToken = null;
+ if (publicVersion != null) {
+ publicVersion.clearAllowlistToken();
+ }
}
/**
@@ -11717,6 +11729,12 @@
mFlags &= ~mask;
}
}
+
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ for (Action action : mActions) {
+ action.visitUris(visitor);
+ }
+ }
}
/**
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index f7d2afb..e1c45d9 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -63,10 +63,11 @@
# Multiuser
per-file *User* = file:/MULTIUSER_OWNERS
-# Notification, DND, Status bar
+# Notification, DND, Status bar, UiModeManager
per-file *Notification* = file:/packages/SystemUI/OWNERS
per-file *Zen* = file:/packages/SystemUI/OWNERS
per-file *StatusBar* = file:/packages/SystemUI/OWNERS
+per-file *UiModeManager* = file:/packages/SystemUI/OWNERS
# PackageManager
per-file ApplicationPackageManager.java = file:/services/core/java/com/android/server/pm/OWNERS
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f3874d5..62209b0 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -64,6 +64,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -391,11 +392,12 @@
void onMarshaled(PendingIntent intent, Parcel parcel, int flags);
}
- private static final ThreadLocal<OnMarshaledListener> sOnMarshaledListener
- = new ThreadLocal<>();
+ private static final ThreadLocal<List<OnMarshaledListener>> sOnMarshaledListener =
+ ThreadLocal.withInitial(ArrayList::new);
/**
- * Registers an listener for pending intents being written to a parcel.
+ * Registers an listener for pending intents being written to a parcel. This replaces any
+ * listeners previously added.
*
* @param listener The listener, null to clear.
*
@@ -403,7 +405,27 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static void setOnMarshaledListener(OnMarshaledListener listener) {
- sOnMarshaledListener.set(listener);
+ final List<OnMarshaledListener> listeners = sOnMarshaledListener.get();
+ listeners.clear();
+ if (listener != null) {
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Adds a listener for pending intents being written to a parcel.
+ * @hide
+ */
+ static void addOnMarshaledListener(OnMarshaledListener listener) {
+ sOnMarshaledListener.get().add(listener);
+ }
+
+ /**
+ * Removes a listener for pending intents being written to a parcel.
+ * @hide
+ */
+ static void removeOnMarshaledListener(OnMarshaledListener listener) {
+ sOnMarshaledListener.get().remove(listener);
}
private static void checkPendingIntent(int flags, @NonNull Intent intent,
@@ -1451,11 +1473,11 @@
public void writeToParcel(Parcel out, int flags) {
out.writeStrongBinder(mTarget.asBinder());
- OnMarshaledListener listener = sOnMarshaledListener.get();
- if (listener != null) {
- listener.onMarshaled(this, out, flags);
+ final List<OnMarshaledListener> listeners = sOnMarshaledListener.get();
+ final int numListeners = listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ listeners.get(i).onMarshaled(this, out, flags);
}
-
}
public static final @NonNull Creator<PendingIntent> CREATOR = new Creator<PendingIntent>() {
@@ -1483,9 +1505,10 @@
@NonNull Parcel out) {
out.writeStrongBinder(sender != null ? sender.mTarget.asBinder() : null);
if (sender != null) {
- OnMarshaledListener listener = sOnMarshaledListener.get();
- if (listener != null) {
- listener.onMarshaled(sender, out, 0 /* flags */);
+ final List<OnMarshaledListener> listeners = sOnMarshaledListener.get();
+ final int numListeners = listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ listeners.get(i).onMarshaled(sender, out, 0 /* flags */);
}
}
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index d90257a..0ccb9cd 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -315,7 +315,7 @@
@SystemApi
public static final int MODE_NIGHT_CUSTOM_TYPE_BEDTIME = 1;
- private IUiModeManager mService;
+ private static Globals sGlobals;
/**
* Context required for getting the opPackageName of API caller; maybe be {@code null} if the
@@ -341,6 +341,60 @@
mOnProjectionStateChangedListenerResourceManager =
new OnProjectionStateChangedListenerResourceManager();
+ private static class Globals extends IUiModeManagerCallback.Stub {
+
+ private final IUiModeManager mService;
+ private final Object mGlobalsLock = new Object();
+
+ private float mContrast = ContrastUtils.CONTRAST_DEFAULT_VALUE;
+
+ /**
+ * Map that stores user provided {@link ContrastChangeListener} callbacks,
+ * and the executors on which these callbacks should be called.
+ */
+ private final ArrayMap<ContrastChangeListener, Executor>
+ mContrastChangeListeners = new ArrayMap<>();
+
+ Globals(IUiModeManager service) {
+ mService = service;
+ try {
+ mService.addCallback(this);
+ mContrast = mService.getContrast();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Setup failed: UiModeManagerService is dead", e);
+ }
+ }
+
+ private float getContrast() {
+ synchronized (mGlobalsLock) {
+ return mContrast;
+ }
+ }
+
+ private void addContrastChangeListener(ContrastChangeListener listener, Executor executor) {
+ synchronized (mGlobalsLock) {
+ mContrastChangeListeners.put(listener, executor);
+ }
+ }
+
+ private void removeContrastChangeListener(ContrastChangeListener listener) {
+ synchronized (mGlobalsLock) {
+ mContrastChangeListeners.remove(listener);
+ }
+ }
+
+ @Override
+ public void notifyContrastChanged(float contrast) {
+ synchronized (mGlobalsLock) {
+ // if value changed in the settings, update the cached value and notify listeners
+ if (Math.abs(mContrast - contrast) < 1e-10) return;
+ mContrast = contrast;
+ mContrastChangeListeners.forEach((listener, executor) -> executor.execute(
+ () -> listener.onContrastChanged(contrast)));
+ }
+ }
+ }
+
/**
* Define constants and conversions between {@link ContrastLevel}s and contrast values.
* <p>
@@ -407,43 +461,18 @@
}
}
- /**
- * Map that stores user provided {@link ContrastChangeListener} callbacks,
- * and the executors on which these callbacks should be called.
- */
- private final ArrayMap<ContrastChangeListener, Executor>
- mContrastChangeListeners = new ArrayMap<>();
- private float mContrast;
-
- private final IUiModeManagerCallback.Stub mCallback = new IUiModeManagerCallback.Stub() {
- @Override
- public void notifyContrastChanged(float contrast) {
- final ArrayMap<ContrastChangeListener, Executor> listeners;
- synchronized (mLock) {
- // if value changed in the settings, update the cached value and notify listeners
- if (Math.abs(mContrast - contrast) < 1e-10) return;
- mContrast = contrast;
- listeners = new ArrayMap<>(mContrastChangeListeners);
- }
- listeners.forEach((listener, executor) -> executor.execute(
- () -> listener.onContrastChanged(mContrast)));
- }
- };
-
@UnsupportedAppUsage
/*package*/ UiModeManager() throws ServiceNotFoundException {
this(null /* context */);
}
/*package*/ UiModeManager(Context context) throws ServiceNotFoundException {
- mService = IUiModeManager.Stub.asInterface(
+ IUiModeManager service = IUiModeManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.UI_MODE_SERVICE));
mContext = context;
- try {
- mService.addCallback(mCallback);
- mContrast = mService.getContrast();
- } catch (RemoteException e) {
- Log.e(TAG, "Setup failed: UiModeManagerService is dead", e);
+ if (service == null) return;
+ synchronized (mLock) {
+ if (sGlobals == null) sGlobals = new Globals(service);
}
}
@@ -533,9 +562,9 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED)
public void enableCarMode(@IntRange(from = 0) int priority, @EnableCarMode int flags) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.enableCarMode(flags, priority,
+ sGlobals.mService.enableCarMode(flags, priority,
mContext == null ? null : mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -585,9 +614,9 @@
* @param flags One of the disable car mode flags.
*/
public void disableCarMode(@DisableCarMode int flags) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.disableCarModeByCallingPackage(flags,
+ sGlobals.mService.disableCarModeByCallingPackage(flags,
mContext == null ? null : mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -606,9 +635,9 @@
* {@link Configuration#UI_MODE_TYPE_VR_HEADSET Configuration.UI_MODE_TYPE_VR_HEADSET}.
*/
public int getCurrentModeType() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.getCurrentModeType();
+ return sGlobals.mService.getCurrentModeType();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -653,9 +682,9 @@
* @see #setApplicationNightMode(int)
*/
public void setNightMode(@NightMode int mode) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.setNightMode(mode);
+ sGlobals.mService.setNightMode(mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -674,9 +703,9 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
public void setNightModeCustomType(@NightModeCustomType int nightModeCustomType) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.setNightModeCustomType(nightModeCustomType);
+ sGlobals.mService.setNightModeCustomType(nightModeCustomType);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -693,9 +722,9 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
public @NightModeCustomReturnType int getNightModeCustomType() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.getNightModeCustomType();
+ return sGlobals.mService.getNightModeCustomType();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -732,9 +761,9 @@
* @see #setNightMode(int)
*/
public void setApplicationNightMode(@NightMode int mode) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.setApplicationNightMode(mode);
+ sGlobals.mService.setApplicationNightMode(mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -757,9 +786,9 @@
* @see #setNightMode(int)
*/
public @NightMode int getNightMode() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.getNightMode();
+ return sGlobals.mService.getNightMode();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -774,9 +803,9 @@
*/
@TestApi
public boolean isUiModeLocked() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.isUiModeLocked();
+ return sGlobals.mService.isUiModeLocked();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -796,9 +825,9 @@
*/
@TestApi
public boolean isNightModeLocked() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.isNightModeLocked();
+ return sGlobals.mService.isNightModeLocked();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -820,9 +849,10 @@
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
public boolean setNightModeActivatedForCustomMode(@NightModeCustomType int nightModeCustomType,
boolean active) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.setNightModeActivatedForCustomMode(nightModeCustomType, active);
+ return sGlobals.mService.setNightModeActivatedForCustomMode(
+ nightModeCustomType, active);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -838,9 +868,9 @@
*/
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
public boolean setNightModeActivated(boolean active) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.setNightModeActivated(active);
+ return sGlobals.mService.setNightModeActivated(active);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -856,9 +886,9 @@
*/
@NonNull
public LocalTime getCustomNightModeStart() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return LocalTime.ofNanoOfDay(mService.getCustomNightModeStart() * 1000);
+ return LocalTime.ofNanoOfDay(sGlobals.mService.getCustomNightModeStart() * 1000);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -874,9 +904,9 @@
* @param time The time of the day Dark theme should activate
*/
public void setCustomNightModeStart(@NonNull LocalTime time) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.setCustomNightModeStart(time.toNanoOfDay() / 1000);
+ sGlobals.mService.setCustomNightModeStart(time.toNanoOfDay() / 1000);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -891,9 +921,9 @@
*/
@NonNull
public LocalTime getCustomNightModeEnd() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return LocalTime.ofNanoOfDay(mService.getCustomNightModeEnd() * 1000);
+ return LocalTime.ofNanoOfDay(sGlobals.mService.getCustomNightModeEnd() * 1000);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -909,9 +939,9 @@
* @param time The time of the day Dark theme should deactivate
*/
public void setCustomNightModeEnd(@NonNull LocalTime time) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.setCustomNightModeEnd(time.toNanoOfDay() / 1000);
+ sGlobals.mService.setCustomNightModeEnd(time.toNanoOfDay() / 1000);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -976,9 +1006,9 @@
@RequiresPermission(value = android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION,
conditional = true)
public boolean requestProjection(@ProjectionType int projectionType) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.requestProjection(new Binder(), projectionType,
+ return sGlobals.mService.requestProjection(new Binder(), projectionType,
mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1005,9 +1035,10 @@
@RequiresPermission(value = android.Manifest.permission.TOGGLE_AUTOMOTIVE_PROJECTION,
conditional = true)
public boolean releaseProjection(@ProjectionType int projectionType) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.releaseProjection(projectionType, mContext.getOpPackageName());
+ return sGlobals.mService.releaseProjection(
+ projectionType, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1028,9 +1059,9 @@
@RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
@NonNull
public Set<String> getProjectingPackages(@ProjectionType int projectionType) {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return new ArraySet<>(mService.getProjectingPackages(projectionType));
+ return new ArraySet<>(sGlobals.mService.getProjectingPackages(projectionType));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1046,9 +1077,9 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PROJECTION_STATE)
public @ProjectionType int getActiveProjectionTypes() {
- if (mService != null) {
+ if (sGlobals != null) {
try {
- return mService.getActiveProjectionTypes();
+ return sGlobals.mService.getActiveProjectionTypes();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1076,11 +1107,12 @@
Slog.i(TAG, "Attempted to add listener that was already added.");
return;
}
- if (mService != null) {
+ if (sGlobals != null) {
InnerListener innerListener = new InnerListener(executor, listener,
mOnProjectionStateChangedListenerResourceManager);
try {
- mService.addOnProjectionStateChangedListener(innerListener, projectionType);
+ sGlobals.mService.addOnProjectionStateChangedListener(
+ innerListener, projectionType);
mProjectionStateListenerMap.put(listener, innerListener);
} catch (RemoteException e) {
mOnProjectionStateChangedListenerResourceManager.remove(innerListener);
@@ -1107,9 +1139,9 @@
Slog.i(TAG, "Attempted to remove listener that was not added.");
return;
}
- if (mService != null) {
+ if (sGlobals != null) {
try {
- mService.removeOnProjectionStateChangedListener(innerListener);
+ sGlobals.mService.removeOnProjectionStateChangedListener(innerListener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1197,15 +1229,10 @@
* <li> -1 corresponds to the minimum contrast </li>
* <li> 1 corresponds to the maximum contrast </li>
* </ul>
- *
- *
- *
*/
@FloatRange(from = -1.0f, to = 1.0f)
public float getContrast() {
- synchronized (mLock) {
- return mContrast;
- }
+ return sGlobals.getContrast();
}
/**
@@ -1219,9 +1246,7 @@
@NonNull ContrastChangeListener listener) {
Objects.requireNonNull(executor);
Objects.requireNonNull(listener);
- synchronized (mLock) {
- mContrastChangeListeners.put(listener, executor);
- }
+ sGlobals.addContrastChangeListener(listener, executor);
}
/**
@@ -1232,8 +1257,6 @@
*/
public void removeContrastChangeListener(@NonNull ContrastChangeListener listener) {
Objects.requireNonNull(listener);
- synchronized (mLock) {
- mContrastChangeListeners.remove(listener);
- }
+ sGlobals.removeContrastChangeListener(listener);
}
}
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index 251c5d8..dd31175 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -30,6 +30,7 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PASSWORD_SIZE;
+import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PATTERN_SIZE;
import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE;
import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS;
@@ -134,17 +135,6 @@
}
}
- private static boolean hasInvalidCharacters(byte[] password) {
- // Allow non-control Latin-1 characters only.
- for (byte b : password) {
- char c = (char) b;
- if (c < 32 || c > 127) {
- return true;
- }
- }
- return false;
- }
-
@Override
public int describeContents() {
return 0;
@@ -189,19 +179,15 @@
};
/**
- * Returns the {@code PasswordMetrics} for a given credential.
- *
- * If the credential is a pin or a password, equivalent to
- * {@link #computeForPasswordOrPin(byte[], boolean)}. {@code credential} cannot be null
- * when {@code type} is
- * {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}.
+ * Returns the {@code PasswordMetrics} for the given credential.
*/
public static PasswordMetrics computeForCredential(LockscreenCredential credential) {
if (credential.isPassword() || credential.isPin()) {
- return PasswordMetrics.computeForPasswordOrPin(credential.getCredential(),
- credential.isPin());
+ return computeForPasswordOrPin(credential.getCredential(), credential.isPin());
} else if (credential.isPattern()) {
- return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
+ PasswordMetrics metrics = new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
+ metrics.length = credential.size();
+ return metrics;
} else if (credential.isNone()) {
return new PasswordMetrics(CREDENTIAL_TYPE_NONE);
} else {
@@ -210,10 +196,10 @@
}
/**
- * Returns the {@code PasswordMetrics} for a given password or pin
+ * Returns the {@code PasswordMetrics} for the given password or pin.
*/
- public static PasswordMetrics computeForPasswordOrPin(byte[] password, boolean isPin) {
- // Analyse the characters used
+ private static PasswordMetrics computeForPasswordOrPin(byte[] credential, boolean isPin) {
+ // Analyze the characters used.
int letters = 0;
int upperCase = 0;
int lowerCase = 0;
@@ -221,8 +207,8 @@
int symbols = 0;
int nonLetter = 0;
int nonNumeric = 0;
- final int length = password.length;
- for (byte b : password) {
+ final int length = credential.length;
+ for (byte b : credential) {
switch (categoryChar((char) b)) {
case CHAR_LOWER_CASE:
letters++;
@@ -247,7 +233,7 @@
}
final int credType = isPin ? CREDENTIAL_TYPE_PIN : CREDENTIAL_TYPE_PASSWORD;
- final int seqLength = maxLengthSequence(password);
+ final int seqLength = maxLengthSequence(credential);
return new PasswordMetrics(credType, length, letters, upperCase, lowerCase,
numeric, symbols, nonLetter, nonNumeric, seqLength);
}
@@ -529,39 +515,8 @@
return Collections.singletonList(
new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0));
}
- if (credential.isPassword() || credential.isPin()) {
- return validatePassword(adminMetrics, minComplexity, credential.isPin(),
- credential.getCredential());
- } else {
- return validatePasswordMetrics(adminMetrics, minComplexity,
- new PasswordMetrics(credential.getType()));
- }
- }
-
- /**
- * Validates a proposed lockscreen credential against minimum metrics and complexity.
- *
- * @param adminMetrics minimum metrics to satisfy admin requirements
- * @param minComplexity minimum complexity imposed by the requester
- * @param isPin whether to validate as a PIN (true) or password (false)
- * @param password the proposed lockscreen credential as a byte[]. Must be the value from
- * {@link LockscreenCredential#getCredential()}.
- *
- * @return a list of validation errors. An empty list means the credential is OK.
- *
- * TODO: merge this into validateCredential() and remove the redundant hasInvalidCharacters(),
- * once all external callers are removed
- */
- public static List<PasswordValidationError> validatePassword(
- PasswordMetrics adminMetrics, int minComplexity, boolean isPin, byte[] password) {
-
- if (hasInvalidCharacters(password)) {
- return Collections.singletonList(
- new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0));
- }
-
- final PasswordMetrics enteredMetrics = computeForPasswordOrPin(password, isPin);
- return validatePasswordMetrics(adminMetrics, minComplexity, enteredMetrics);
+ PasswordMetrics actualMetrics = computeForCredential(credential);
+ return validatePasswordMetrics(adminMetrics, minComplexity, actualMetrics);
}
/**
@@ -584,9 +539,18 @@
|| !bucket.allowsCredType(actualMetrics.credType)) {
return Collections.singletonList(new PasswordValidationError(WEAK_CREDENTIAL_TYPE, 0));
}
- if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD
- && actualMetrics.credType != CREDENTIAL_TYPE_PIN) {
- return Collections.emptyList(); // Nothing to check for pattern or none.
+ if (actualMetrics.credType == CREDENTIAL_TYPE_PATTERN) {
+ // For pattern, only need to check the length against the hardcoded minimum. If the
+ // pattern length is unavailable (e.g., PasswordMetrics that was stored on-disk before
+ // the pattern length started being included in it), assume it is okay.
+ if (actualMetrics.length != 0 && actualMetrics.length < MIN_LOCK_PATTERN_SIZE) {
+ return Collections.singletonList(new PasswordValidationError(TOO_SHORT,
+ MIN_LOCK_PATTERN_SIZE));
+ }
+ return Collections.emptyList();
+ }
+ if (actualMetrics.credType == CREDENTIAL_TYPE_NONE) {
+ return Collections.emptyList(); // Nothing to check for none.
}
if (actualMetrics.credType == CREDENTIAL_TYPE_PIN && actualMetrics.nonNumeric > 0) {
diff --git a/core/java/android/content/pm/Checksum.java b/core/java/android/content/pm/Checksum.java
index ff17496..2096727 100644
--- a/core/java/android/content/pm/Checksum.java
+++ b/core/java/android/content/pm/Checksum.java
@@ -40,11 +40,11 @@
/**
* Root SHA256 hash of a 4K Merkle tree computed over all file bytes.
* <a href="https://source.android.com/security/apksigning/v4">See APK Signature Scheme V4</a>.
- * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst">See fs-verity</a>.
+ * <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html">See fs-verity</a>.
*
* Recommended for all new applications.
* Can be used by kernel to enforce authenticity and integrity of the APK.
- * <a href="https://git.kernel.org/pub/scm/fs/fscrypt/fscrypt.git/tree/Documentation/filesystems/fsverity.rst#">See fs-verity for details</a>
+ * <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html">See fs-verity for details</a>
*
* @see PackageManager#requestChecksums
*/
diff --git a/core/java/android/content/pm/SigningDetails.java b/core/java/android/content/pm/SigningDetails.java
index 1e659b7..af2649f 100644
--- a/core/java/android/content/pm/SigningDetails.java
+++ b/core/java/android/content/pm/SigningDetails.java
@@ -867,10 +867,12 @@
return false;
}
// The capabilities for the past signing certs must match as well.
- for (int i = 0; i < mPastSigningCertificates.length; i++) {
- if (mPastSigningCertificates[i].getFlags()
- != that.mPastSigningCertificates[i].getFlags()) {
- return false;
+ if (mPastSigningCertificates != null) {
+ for (int i = 0; i < mPastSigningCertificates.length; i++) {
+ if (mPastSigningCertificates[i].getFlags()
+ != that.mPastSigningCertificates[i].getFlags()) {
+ return false;
+ }
}
}
return true;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 026b8c2..eceec34 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -2171,11 +2171,11 @@
* Return a {@link SQLiteRawStatement} connected to the database. A transaction must be in
* progress or an exception will be thrown. The resulting object will be closed automatically
* when the current transaction closes.
+ *
* @param sql The SQL string to be compiled into a prepared statement.
* @return A {@link SQLiteRawStatement} holding the compiled SQL.
* @throws IllegalStateException if a transaction is not in progress.
* @throws SQLiteException if the SQL cannot be compiled.
- * @hide
*/
@NonNull
public SQLiteRawStatement createRawStatement(@NonNull String sql) {
@@ -2184,16 +2184,19 @@
}
/**
- * Return the "rowid" of the last row to be inserted on the current connection. See the
- * SQLite documentation for the specific details. This method must only be called when inside
- * a transaction. {@link IllegalStateException} is thrown if the method is called outside a
- * transaction. If the function is called before any inserts in the current transaction, the
- * value returned will be from a previous transaction, which may be from a different thread.
+ * Return the "rowid" of the last row to be inserted on the current connection. This method must
+ * only be called when inside a transaction. {@link IllegalStateException} is thrown if the
+ * method is called outside a transaction. If the function is called before any inserts in the
+ * current transaction, the value returned will be from a previous transaction, which may be
+ * from a different thread. If no inserts have occurred on the current connection, the function
+ * returns 0. See the SQLite documentation for the specific details.
+ *
+ * @see <a href="https://sqlite.org/c3ref/last_insert_rowid.html">sqlite3_last_insert_rowid</a>
+ *
* @return The ROWID of the last row to be inserted under this connection.
* @throws IllegalStateException if there is no current transaction.
- * @hide
*/
- public long lastInsertRowId() {
+ public long getLastInsertRowId() {
return getThreadSession().lastInsertRowId();
}
diff --git a/core/java/android/database/sqlite/SQLiteRawStatement.java b/core/java/android/database/sqlite/SQLiteRawStatement.java
index 6b43788..165f181 100644
--- a/core/java/android/database/sqlite/SQLiteRawStatement.java
+++ b/core/java/android/database/sqlite/SQLiteRawStatement.java
@@ -31,10 +31,10 @@
import java.util.Objects;
/**
- * Represents a SQLite statement. The methods correspond very closely to SQLite APIs that operate
- * on a sqlite_stmt object. See the SQLite API documentation for complete details. In general,
- * the APIs in this class correspond to the SQLite APIs with the same name, except that snake-case
- * is changed to camel-case.
+ * A {@link SQLiteRawStatement} represents a SQLite prepared statement. The methods correspond very
+ * closely to SQLite APIs that operate on a sqlite_stmt object. In general, each API in this class
+ * corresponds to a single SQLite API.
+
* <p>
* A {@link SQLiteRawStatement} must be created through a database, and there must be a
* transaction open at the time. Statements are implicitly closed when the outermost transaction
@@ -66,8 +66,9 @@
* database.endTransaction();
* }
* </pre></code>
- * Note that this class is unrelated to {@link SQLiteStatement}.
- * @hide
+ * Note that {@link SQLiteRawStatement} is unrelated to {@link SQLiteStatement}.
+ *
+ * @see <a href="http://sqlite.org/c3ref/stmt.html">sqlite3_stmt</a>
*/
public final class SQLiteRawStatement implements Closeable {
@@ -114,24 +115,46 @@
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, SQLITE_NULL})
+ @IntDef(value = {
+ SQLITE_DATA_TYPE_INTEGER,
+ SQLITE_DATA_TYPE_FLOAT,
+ SQLITE_DATA_TYPE_TEXT,
+ SQLITE_DATA_TYPE_BLOB,
+ SQLITE_DATA_TYPE_NULL})
public @interface SQLiteDataType {}
- public static final int SQLITE_INTEGER = 1;
- public static final int SQLITE_FLOAT = 2;
- public static final int SQLITE_TEXT = 3;
- public static final int SQLITE_BLOB = 4;
- public static final int SQLITE_NULL = 5;
+ /**
+ * The constant returned by {@link #getColumnType} when the column value is SQLITE_INTEGER.
+ */
+ public static final int SQLITE_DATA_TYPE_INTEGER = 1;
/**
- * SQLite error codes that are used by this class. Refer to the sqlite documentation for
- * other error codes.
+ * The constant returned by {@link #getColumnType} when the column value is SQLITE_FLOAT.
*/
- public static final int SQLITE_OK = 0;
- public static final int SQLITE_BUSY = 5;
- public static final int SQLITE_LOCKED = 6;
- public static final int SQLITE_ROW = 100;
- public static final int SQLITE_DONE = 101;
+ public static final int SQLITE_DATA_TYPE_FLOAT = 2;
+
+ /**
+ * The constant returned by {@link #getColumnType} when the column value is SQLITE_TEXT.
+ */
+ public static final int SQLITE_DATA_TYPE_TEXT = 3;
+
+ /**
+ * The constant returned by {@link #getColumnType} when the column value is SQLITE_BLOB.
+ */
+ public static final int SQLITE_DATA_TYPE_BLOB = 4;
+
+ /**
+ * The constant returned by {@link #getColumnType} when the column value is SQLITE_NULL.
+ */
+ public static final int SQLITE_DATA_TYPE_NULL = 5;
+
+ /**
+ * SQLite error codes that are used by this class.
+ */
+ private static final int SQLITE_BUSY = 5;
+ private static final int SQLITE_LOCKED = 6;
+ private static final int SQLITE_ROW = 100;
+ private static final int SQLITE_DONE = 101;
/**
* Create the statement with empty bindings. The construtor will throw
@@ -201,6 +224,7 @@
/**
* Return true if the statement is still open and false otherwise.
+ *
* @return True if the statement is open.
*/
public boolean isOpen() {
@@ -208,9 +232,12 @@
}
/**
- * Step to the next result. This returns true if the statement stepped to a new row, and
+ * Step to the next result row. This returns true if the statement stepped to a new row, and
* false if the statement is done. The method throws on any other result, including a busy or
* locked database. If WAL is enabled then the database should never be locked or busy.
+ *
+ * @see <a href="http://sqlite.org/c3ref/step.html">sqlite3_step</a>
+ *
* @return True if a row is available and false otherwise.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteDatabaseLockedException if the database is locked or busy.
@@ -239,11 +266,14 @@
}
/**
- * Step to the next result. This returns the raw error code code from the native method. The
+ * Step to the next result. This returns the raw result code code from the native method. The
* expected values are SQLITE_ROW and SQLITE_DONE. For other return values, clients must
- * decode the error and handle it themselves.
+ * decode the error and handle it themselves. http://sqlite.org/rescode.html for the current
+ * list of result codes.
+ *
* @return The native result code from the sqlite3_step() operation.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
+ * @hide
*/
public int stepNoThrow() {
throwIfInvalid();
@@ -255,8 +285,10 @@
}
/**
- * Reset the statement. The sqlite3 API returns an error code if the last call to step
- * generated an error; this function discards those error codes.
+ * Reset the statement.
+ *
+ * @see <a href="http://sqlite.org/c3ref/reset.html">sqlite3_reset</a>
+ *
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteException if a native error occurs.
*/
@@ -271,6 +303,9 @@
/**
* Clear all parameter bindings.
+ *
+ * @see <a href="http://sqlite.org/c3ref/clear_bindings.html">sqlite3_clear_bindings</a>
+ *
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteException if a native error occurs.
*/
@@ -285,10 +320,14 @@
/**
* Return the number of parameters in the statement.
+ *
+ * @see
+ * <a href="http://sqlite.org/c3ref/bind_parameter_count.html">sqlite3_bind_parameter_count</a>
+ *
* @return The number of parameters in the statement.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
*/
- public int bindParameterCount() {
+ public int getParameterCount() {
throwIfInvalid();
try {
return nativeBindParameterCount(mStatement);
@@ -300,11 +339,15 @@
/**
* Return the index of the parameter with specified name. If the name does not match any
* parameter, 0 is returned.
+ *
+ * @see
+ * <a href="http://sqlite.org/c3ref/bind_parameter_index.html">sqlite3_bind_parameter_index</a>
+ *
* @param name The name of a parameter.
* @return The index of the parameter or 0 if the name does not identify a parameter.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
*/
- public int bindParameterIndex(@NonNull String name) {
+ public int getParameterIndex(@NonNull String name) {
Objects.requireNonNull(name);
throwIfInvalid();
try {
@@ -317,16 +360,19 @@
/**
* Return the name of the parameter at the specified index. Null is returned if there is no
* such parameter or if the parameter does not have a name.
- * @param parameter The index of the parameter.
+ *
+ * @see
+ * <a href="http://sqlite.org/c3ref/bind_parameter_name.html">sqlite3_bind_parameter_name</a>
+ *
+ * @param parameterIndex The index of the parameter.
* @return The name of the parameter.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
- * @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
*/
@Nullable
- public String bindParameterName(int parameter) {
+ public String getParameterName(int parameterIndex) {
throwIfInvalid();
try {
- return nativeBindParameterName(mStatement, parameter);
+ return nativeBindParameterName(mStatement, parameterIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -335,17 +381,20 @@
/**
* Bind a blob to a parameter. Parameter indices start at 1. The function throws if the
* parameter index is out of bounds.
- * @param parameter The index of the parameter in the query. It is one-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/bind_blob.html">sqlite3_bind_blob</a>
+ *
+ * @param parameterIndex The index of the parameter in the query. It is one-based.
* @param value The value to be bound to the parameter.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public void bindBlob(int parameter, @NonNull byte[] value) throws SQLiteException {
+ public void bindBlob(int parameterIndex, @NonNull byte[] value) throws SQLiteException {
Objects.requireNonNull(value);
throwIfInvalid();
try {
- nativeBindBlob(mStatement, parameter, value, 0, value.length);
+ nativeBindBlob(mStatement, parameterIndex, value, 0, value.length);
} finally {
Reference.reachabilityFence(this);
}
@@ -355,7 +404,10 @@
* Bind a blob to a parameter. Parameter indices start at 1. The function throws if the
* parameter index is out of bounds. The sub-array value[offset] to value[offset+length-1] is
* bound.
- * @param parameter The index of the parameter in the query. It is one-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/bind_blob.html">sqlite3_bind_blob</a>
+ *
+ * @param parameterIndex The index of the parameter in the query. It is one-based.
* @param value The value to be bound to the parameter.
* @param offset An offset into the value array
* @param length The number of bytes to bind from the value array.
@@ -364,13 +416,13 @@
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public void bindBlob(int parameter, @NonNull byte[] value, int offset, int length)
+ public void bindBlob(int parameterIndex, @NonNull byte[] value, int offset, int length)
throws SQLiteException {
Objects.requireNonNull(value);
throwIfInvalid();
throwIfInvalidBounds(value.length, offset, length);
try {
- nativeBindBlob(mStatement, parameter, value, offset, length);
+ nativeBindBlob(mStatement, parameterIndex, value, offset, length);
} finally {
Reference.reachabilityFence(this);
}
@@ -379,16 +431,19 @@
/**
* Bind a double to a parameter. Parameter indices start at 1. The function throws if the
* parameter index is out of bounds.
- * @param parameter The index of the parameter in the query. It is one-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/bind_blob.html">sqlite3_bind_double</a>
+ *
+ * @param parameterIndex The index of the parameter in the query. It is one-based.
* @param value The value to be bound to the parameter.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public void bindDouble(int parameter, double value) throws SQLiteException {
+ public void bindDouble(int parameterIndex, double value) throws SQLiteException {
throwIfInvalid();
try {
- nativeBindDouble(mStatement, parameter, value);
+ nativeBindDouble(mStatement, parameterIndex, value);
} finally {
Reference.reachabilityFence(this);
}
@@ -397,15 +452,18 @@
/**
* Bind an int to a parameter. Parameter indices start at 1. The function throws if the
* parameter index is out of bounds.
- * @param parameter The index of the parameter in the query. It is one-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/bind_blob.html">sqlite3_bind_int</a>
+ *
+ * @param parameterIndex The index of the parameter in the query. It is one-based.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public void bindInt(int parameter, int value) throws SQLiteException {
+ public void bindInt(int parameterIndex, int value) throws SQLiteException {
throwIfInvalid();
try {
- nativeBindInt(mStatement, parameter, value);
+ nativeBindInt(mStatement, parameterIndex, value);
} finally {
Reference.reachabilityFence(this);
}
@@ -414,15 +472,18 @@
/**
* Bind a long to the parameter. Parameter indices start at 1. The function throws if the
* parameter index is out of bounds.
+ *
+ * @see <a href="http://sqlite.org/c3ref/bind_blob.html">sqlite3_bind_int64</a>
+ *
* @param value The value to be bound to the parameter.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public void bindLong(int parameter, long value) throws SQLiteException {
+ public void bindLong(int parameterIndex, long value) throws SQLiteException {
throwIfInvalid();
try {
- nativeBindLong(mStatement, parameter, value);
+ nativeBindLong(mStatement, parameterIndex, value);
} finally {
Reference.reachabilityFence(this);
}
@@ -431,15 +492,18 @@
/**
* Bind a null to the parameter. Parameter indices start at 1. The function throws if the
* parameter index is out of bounds.
- * @param parameter The index of the parameter in the query. It is one-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/bind_blob.html">sqlite3_bind_null</a>
+ *
+ * @param parameterIndex The index of the parameter in the query. It is one-based.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public void bindNull(int parameter) throws SQLiteException {
+ public void bindNull(int parameterIndex) throws SQLiteException {
throwIfInvalid();
try {
- nativeBindNull(mStatement, parameter);
+ nativeBindNull(mStatement, parameterIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -448,17 +512,20 @@
/**
* Bind a string to the parameter. Parameter indices start at 1. The function throws if the
* parameter index is out of bounds. The string may not be null.
- * @param parameter The index of the parameter in the query. It is one-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/bind_blob.html">sqlite3_bind_text16</a>
+ *
+ * @param parameterIndex The index of the parameter in the query. It is one-based.
* @param value The value to be bound to the parameter.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the parameter is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public void bindText(int parameter, @NonNull String value) throws SQLiteException {
+ public void bindText(int parameterIndex, @NonNull String value) throws SQLiteException {
Objects.requireNonNull(value);
throwIfInvalid();
try {
- nativeBindText(mStatement, parameter, value);
+ nativeBindText(mStatement, parameterIndex, value);
} finally {
Reference.reachabilityFence(this);
}
@@ -466,10 +533,13 @@
/**
* Return the number of columns in the current result row.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_count.html">sqlite3_column_count</a>
+ *
* @return The number of columns in the result row.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
*/
- public int getResultColumnsCount() {
+ public int getResultColumnCount() {
throwIfInvalid();
try {
return nativeColumnCount(mStatement);
@@ -480,17 +550,20 @@
/**
* Return the type of the column in the result row. Column indices start at 0.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_type</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The type of the value in the column of the result row.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
@SQLiteDataType
- public int getType(int column) throws SQLiteException {
+ public int getColumnType(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnType(mStatement, column);
+ return nativeColumnType(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -499,17 +572,20 @@
/**
* Return the name of the column in the result row. Column indices start at 0. This throws
* an exception if column is not in the result.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_name.html">sqlite3_column_name</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The name of the column in the result row.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteOutOfMemoryException if the database cannot allocate memory for the name.
*/
@NonNull
- public String getName(int column) throws SQLiteException {
+ public String getColumnName(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnName(mStatement, column);
+ return nativeColumnName(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -517,20 +593,24 @@
/**
* Return the length of the column value in the result row. Column indices start at 0. This
- * returns 0 for a null and number of bytes for text or blob. Numeric values are converted to
- * a string and the length of the string is returned. Note that this cannot be used to
- * distinguish a null value from an empty text or blob. Note that this returns the number of
- * bytes in the text value, not the number of characters.
- * @param column The index of a column in the result row. It is zero-based.
+ * returns 0 for a null and number of bytes for text or blob. Numeric values are converted to a
+ * string and the length of the string is returned. See the sqlite documentation for
+ * details. Note that this cannot be used to distinguish a null value from an empty text or
+ * blob. Note that this returns the number of bytes in the text value, not the number of
+ * characters.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_bytes</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The length, in bytes, of the value in the column.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public int getLength(int column) throws SQLiteException {
+ public int getColumnLength(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnBytes(mStatement, column);
+ return nativeColumnBytes(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -540,39 +620,23 @@
* Return the column value of the result row as a blob. Column indices start at 0. This
* throws an exception if column is not in the result. This returns null if the column value
* is null.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * The column value will be converted if it is not of type {@link #SQLITE_DATA_TYPE_BLOB}; see
+ * the sqlite documentation for details.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_blob</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The value of the column as a blob, or null if the column is NULL.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
@Nullable
- public byte[] getBlob(int column) throws SQLiteException {
+ public byte[] getColumnBlob(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnBlob(mStatement, column);
- } finally {
- Reference.reachabilityFence(this);
- }
- }
-
- /**
- * Copy the column value of the result row, interpreted as a blob, into the buffer. Column
- * indices start at 0. This throws an exception if column is not in the result row. Bytes are
- * copied into the buffer until the buffer is full or the end of the blob value is reached.
- * The function returns the number of bytes copied.
- * @param column The index of a column in the result row. It is zero-based.
- * @param buffer A pre-allocated array to be filled with the value of the column.
- * @return the number of bytes that were copied
- * @throws IllegalStateException if the statement is closed or this is a foreign thread.
- * @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
- * @throws SQLiteException if a native error occurs.
- */
- public int getBlob(int column, @NonNull byte[] buffer) throws SQLiteException {
- Objects.requireNonNull(buffer);
- throwIfInvalid();
- try {
- return nativeColumnBuffer(mStatement, column, buffer, 0, buffer.length, 0);
+ return nativeColumnBlob(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -584,7 +648,13 @@
* copied into the buffer starting at the offset. Bytes are copied from the blob starting at
* srcOffset. Length bytes are copied unless the column value has fewer bytes available. The
* function returns the number of bytes copied.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * The column value will be converted if it is not of type {@link #SQLITE_DATA_TYPE_BLOB}; see
+ * the sqlite documentation for details.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_blob</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @param buffer A pre-allocated array to be filled with the value of the column.
* @param offset An offset into the buffer: copying starts here.
* @param length The number of bytes to copy.
@@ -595,13 +665,14 @@
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public int getBlob(int column, @NonNull byte[] buffer, int offset, int length, int srcOffset)
+ public int readColumnBlob(int columnIndex, @NonNull byte[] buffer, int offset,
+ int length, int srcOffset)
throws SQLiteException {
Objects.requireNonNull(buffer);
throwIfInvalid();
throwIfInvalidBounds(buffer.length, offset, length);
try {
- return nativeColumnBuffer(mStatement, column, buffer, offset, length, srcOffset);
+ return nativeColumnBuffer(mStatement, columnIndex, buffer, offset, length, srcOffset);
} finally {
Reference.reachabilityFence(this);
}
@@ -610,16 +681,22 @@
/**
* Return the column value as a double. Column indices start at 0. This throws an exception
* if column is not in the result.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * The column value will be converted if it is not of type {@link #SQLITE_DATA_TYPE_FLOAT}; see
+ * the sqlite documentation for details.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_double</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The value of a column as a double.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public double getDouble(int column) throws SQLiteException {
+ public double getColumnDouble(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnDouble(mStatement, column);
+ return nativeColumnDouble(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -628,16 +705,22 @@
/**
* Return the column value as a int. Column indices start at 0. This throws an exception if
* column is not in the result.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * The column value will be converted if it is not of type {@link #SQLITE_DATA_TYPE_INTEGER};
+ * see the sqlite documentation for details.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_int</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The value of the column as an int.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public int getInt(int column) throws SQLiteException {
+ public int getColumnInt(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnInt(mStatement, column);
+ return nativeColumnInt(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -646,16 +729,22 @@
/**
* Return the column value as a long. Column indices start at 0. This throws an exception if
* column is not in the result.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * The column value will be converted if it is not of type {@link #SQLITE_DATA_TYPE_INTEGER};
+ * see the sqlite documentation for details.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_long</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The value of the column as an long.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
- public long getLong(int column) throws SQLiteException {
+ public long getColumnLong(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnLong(mStatement, column);
+ return nativeColumnLong(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -664,17 +753,23 @@
/**
* Return the column value as a text. Column indices start at 0. This throws an exception if
* column is not in the result.
- * @param column The index of a column in the result row. It is zero-based.
+ *
+ * The column value will be converted if it is not of type {@link #SQLITE_DATA_TYPE_TEXT}; see
+ * the sqlite documentation for details.
+ *
+ * @see <a href="http://sqlite.org/c3ref/column_blob.html">sqlite3_column_text16</a>
+ *
+ * @param columnIndex The index of a column in the result row. It is zero-based.
* @return The value of the column as a string.
* @throws IllegalStateException if the statement is closed or this is a foreign thread.
* @throws SQLiteBindOrColumnIndexOutOfRangeException if the column is out of range.
* @throws SQLiteException if a native error occurs.
*/
@NonNull
- public String getText(int column) throws SQLiteException {
+ public String getColumnText(int columnIndex) throws SQLiteException {
throwIfInvalid();
try {
- return nativeColumnText(mStatement, column);
+ return nativeColumnText(mStatement, columnIndex);
} finally {
Reference.reachabilityFence(this);
}
@@ -732,14 +827,16 @@
private static native void nativeBindText(long stmt, int param, String val);
/**
- * Methods that return information (including the values) of columns from the current result
- * row.
+ * Methods that return information about the columns int the current result row.
*/
@FastNative
private static native int nativeColumnType(long stmt, int col);
@FastNative
private static native String nativeColumnName(long stmt, int col);
+ /**
+ * Methods that return information about the value columns in the current result row.
+ */
@FastNative
private static native int nativeColumnBytes(long stmt, int col);
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 9d5073e..7080133 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -177,5 +177,5 @@
// Internal operation used to clear face biometric scheduler.
// Ensures that the scheduler is not stuck.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
- void scheduleWatchdog();
+ oneway void scheduleWatchdog();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 9975852..e2840ec 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -213,5 +213,5 @@
// Internal operation used to clear fingerprint biometric scheduler.
// Ensures that the scheduler is not stuck.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
- void scheduleWatchdog();
+ oneway void scheduleWatchdog();
}
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index c0877d3..e886f68 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -54,6 +54,7 @@
import android.view.PointerIcon;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
@@ -140,23 +141,27 @@
}
/**
- * Gets an instance of the input manager.
- *
- * @return The input manager instance.
+ * A test session tracker for InputManagerGlobal.
+ * @see #createTestSession(IInputManager)
*/
- public static InputManagerGlobal resetInstance(IInputManager inputManagerService) {
- synchronized (InputManager.class) {
- sInstance = new InputManagerGlobal(inputManagerService);
- return sInstance;
- }
+ @VisibleForTesting
+ public interface TestSession extends AutoCloseable {
+ @Override
+ void close();
}
/**
- * Clear the instance of the input manager.
+ * Create and set a test instance of InputManagerGlobal.
+ *
+ * @return The test session. The session must be {@link TestSession#close()}-ed at the end
+ * of the test.
*/
- public static void clearInstance() {
+ @VisibleForTesting
+ public static TestSession createTestSession(IInputManager inputManagerService) {
synchronized (InputManagerGlobal.class) {
- sInstance = null;
+ final var oldInstance = sInstance;
+ sInstance = new InputManagerGlobal(inputManagerService);
+ return () -> sInstance = oldInstance;
}
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 7664bad..ff8e3a0 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -112,16 +112,14 @@
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_OFF = 0;
// Values for ANGLE_GL_DRIVER_SELECTION_VALUES
+ private static final String ANGLE_GL_DRIVER_CHOICE_DEFAULT = "default";
+ private static final String ANGLE_GL_DRIVER_CHOICE_ANGLE = "angle";
+ private static final String ANGLE_GL_DRIVER_CHOICE_NATIVE = "native";
+
private enum AngleDriverChoice {
- DEFAULT("default"),
- ANGLE("angle"),
- NATIVE("native");
-
- public final String choice;
-
- AngleDriverChoice(String choice) {
- this.choice = choice;
- }
+ DEFAULT,
+ ANGLE,
+ NATIVE,
}
private static final String PROPERTY_RO_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
@@ -493,9 +491,9 @@
Log.v(TAG,
"ANGLE Developer option for '" + packageName + "' "
+ "set to: '" + optInValue + "'");
- if (optInValue.equals(AngleDriverChoice.ANGLE.choice)) {
+ if (optInValue.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE)) {
return AngleDriverChoice.ANGLE;
- } else if (optInValue.equals(AngleDriverChoice.NATIVE.choice)) {
+ } else if (optInValue.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)) {
return AngleDriverChoice.NATIVE;
} else {
// The user either chose default or an invalid value; go with the default driver or what
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7a05568..06cce11 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2199,6 +2199,16 @@
= "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS";
/**
+ * Intent Extra: The value of {@link android.app.settings.SettingsEnums#EntryPointType} for
+ * settings metrics that logs the entry point about physical keyboard settings.
+ * <p>
+ * This must be passed as an extra field to the {@link #ACTION_HARD_KEYBOARD_SETTINGS}.
+ * @hide
+ */
+ public static final String EXTRA_ENTRYPOINT =
+ "com.android.settings.inputmethod.EXTRA_ENTRYPOINT";
+
+ /**
* Activity Extra: The package owner of the notification channel settings to display.
* <p>
* This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}.
@@ -2785,6 +2795,9 @@
/** @hide - Private call() method to reset to defaults the 'configuration' table */
public static final String CALL_METHOD_DELETE_CONFIG = "DELETE_config";
+ /** @hide - Private call() method to reset to defaults the 'system' table */
+ public static final String CALL_METHOD_RESET_SYSTEM = "RESET_system";
+
/** @hide - Private call() method to reset to defaults the 'secure' table */
public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
@@ -4000,6 +4013,26 @@
overrideableByRestore);
}
+ /**
+ * Store a name/value pair into the database.
+ *
+ * @param resolver to access the database with
+ * @param name to store
+ * @param value to associate with the name
+ * @param makeDefault whether to make the value the default one
+ * @param overrideableByRestore whether restore can override this value
+ * @return true if the value was set, false on database errors
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE)
+ @SystemApi
+ public static boolean putString(@NonNull ContentResolver resolver, @NonNull String name,
+ @Nullable String value, boolean makeDefault, boolean overrideableByRestore) {
+ return putStringForUser(resolver, name, value, /* tag= */ null,
+ makeDefault, resolver.getUserId(), overrideableByRestore);
+ }
+
/** @hide */
@UnsupportedAppUsage
public static boolean putStringForUser(ContentResolver resolver, String name, String value,
@@ -4035,6 +4068,60 @@
}
/**
+ * Reset the settings to their defaults. This would reset <strong>only</strong>
+ * settings set by the caller's package. Think of it of a way to undo your own
+ * changes to the system settings. Passing in the optional tag will reset only
+ * settings changed by your package and associated with this tag.
+ *
+ * @param resolver Handle to the content resolver.
+ * @param tag Optional tag which should be associated with the settings to reset.
+ *
+ * @see #putString(ContentResolver, String, String, boolean, boolean)
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void resetToDefaults(@NonNull ContentResolver resolver,
+ @Nullable String tag) {
+ resetToDefaultsAsUser(resolver, tag, RESET_MODE_PACKAGE_DEFAULTS,
+ resolver.getUserId());
+ }
+
+ /**
+ * Reset the settings to their defaults for a given user with a specific mode. The
+ * optional tag argument is valid only for {@link #RESET_MODE_PACKAGE_DEFAULTS}
+ * allowing resetting the settings made by a package and associated with the tag.
+ *
+ * @param resolver Handle to the content resolver.
+ * @param tag Optional tag which should be associated with the settings to reset.
+ * @param mode The reset mode.
+ * @param userHandle The user for which to reset to defaults.
+ *
+ * @see #RESET_MODE_PACKAGE_DEFAULTS
+ * @see #RESET_MODE_UNTRUSTED_DEFAULTS
+ * @see #RESET_MODE_UNTRUSTED_CHANGES
+ * @see #RESET_MODE_TRUSTED_DEFAULTS
+ *
+ * @hide
+ */
+ public static void resetToDefaultsAsUser(@NonNull ContentResolver resolver,
+ @Nullable String tag, @ResetMode int mode, @IntRange(from = 0) int userHandle) {
+ try {
+ Bundle arg = new Bundle();
+ arg.putInt(CALL_METHOD_USER_KEY, userHandle);
+ if (tag != null) {
+ arg.putString(CALL_METHOD_TAG_KEY, tag);
+ }
+ arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
+ IContentProvider cp = sProviderHolder.getProvider(resolver);
+ cp.call(resolver.getAttributionSource(),
+ sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_SYSTEM, null, arg);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
+ }
+ }
+
+ /**
* Construct the content URI for a particular name/value pair,
* useful for monitoring changes with a ContentObserver.
* @param name to look up in the table
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 7fa0ac8..06e86af 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -15,6 +15,8 @@
*/
package android.service.contentcapture;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_PAUSED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_RESUMED;
import static android.view.contentcapture.ContentCaptureHelper.sDebug;
import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
import static android.view.contentcapture.ContentCaptureHelper.toList;
@@ -569,7 +571,16 @@
List<ContentCaptureEvent> events = parceledEvents.getList();
int sessionIdInt = events.isEmpty() ? NO_SESSION_ID : events.get(0).getSessionId();
ContentCaptureSessionId sessionId = new ContentCaptureSessionId(sessionIdInt);
+
+ ContentCaptureEvent startEvent =
+ new ContentCaptureEvent(sessionIdInt, TYPE_SESSION_RESUMED);
+ startEvent.setSelectionIndex(0, events.size());
+ onContentCaptureEvent(sessionId, startEvent);
+
events.forEach(event -> onContentCaptureEvent(sessionId, event));
+
+ ContentCaptureEvent endEvent = new ContentCaptureEvent(sessionIdInt, TYPE_SESSION_PAUSED);
+ onContentCaptureEvent(sessionId, endEvent);
}
private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c1eacb5..1d58268 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -302,11 +302,9 @@
public static final int ANIMATION_TYPE_NONE = -1;
/** Running animation will show insets */
- @VisibleForTesting
public static final int ANIMATION_TYPE_SHOW = 0;
/** Running animation will hide insets */
- @VisibleForTesting
public static final int ANIMATION_TYPE_HIDE = 1;
/** Running animation is controlled by user via {@link #controlWindowInsetsAnimation} */
@@ -447,21 +445,21 @@
if (mInputMethodJankContext == null) return;
ImeTracker.forJank().onRequestAnimation(
mInputMethodJankContext,
- mShow ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
+ getAnimationType(),
!mHasAnimationCallbacks);
}
@Override
public void onAnimationCancel(Animator animation) {
if (mInputMethodJankContext == null) return;
- ImeTracker.forJank().onCancelAnimation();
+ ImeTracker.forJank().onCancelAnimation(getAnimationType());
}
@Override
public void onAnimationEnd(Animator animation) {
onAnimationFinish();
if (mInputMethodJankContext == null) return;
- ImeTracker.forJank().onFinishAnimation();
+ ImeTracker.forJank().onFinishAnimation(getAnimationType());
}
});
if (!mHasAnimationCallbacks) {
@@ -562,6 +560,14 @@
}
}
}
+
+ /**
+ * Returns the current animation type.
+ */
+ @AnimationType
+ private int getAnimationType() {
+ return mShow ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE;
+ }
}
/**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 858da55..bb4cc8f 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -2066,6 +2066,7 @@
case KeyEvent.KEYCODE_STEM_2:
case KeyEvent.KEYCODE_STEM_3:
case KeyEvent.KEYCODE_WAKEUP:
+ case KeyEvent.KEYCODE_STEM_PRIMARY:
return true;
}
return false;
diff --git a/core/java/android/view/NotificationTopLineView.java b/core/java/android/view/NotificationTopLineView.java
index bd20f5b..a2919f5 100644
--- a/core/java/android/view/NotificationTopLineView.java
+++ b/core/java/android/view/NotificationTopLineView.java
@@ -21,6 +21,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.os.Trace;
import android.util.AttributeSet;
import android.widget.RemoteViews;
@@ -106,6 +107,7 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ Trace.beginSection("NotificationTopLineView#onMeasure");
final int givenWidth = MeasureSpec.getSize(widthMeasureSpec);
final int givenHeight = MeasureSpec.getSize(heightMeasureSpec);
final boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
@@ -161,6 +163,7 @@
.finish();
}
setMeasuredDimension(givenWidth, wrapHeight ? maxChildHeight : givenHeight);
+ Trace.endSection();
}
@Override
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 1e268be..5b69d7f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1340,7 +1340,7 @@
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession)
.setName(name)
.setLocalOwnerView(this)
- .setParent(viewRoot.getBoundsLayer())
+ .setParent(viewRoot.updateAndGetBoundsLayer(surfaceUpdateTransaction))
.setCallsite("SurfaceView.updateSurface")
.setContainerLayer()
.build();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bf8c0d2..9f1cc71 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -32104,9 +32104,7 @@
return false;
}
- getLocationInWindow(mAttachInfo.mTmpLocation);
- return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft()
- && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop();
+ return true;
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1d90270..379d1d87 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -715,9 +715,9 @@
/**
* Child container layer of {@code mSurface} with the same bounds as its parent, and cropped to
- * the surface insets. This surface is created only if a client requests it via {@link
- * #getBoundsLayer()}. By parenting to this bounds surface, child surfaces can ensure they do
- * not draw into the surface inset region set by the parent window.
+ * the surface insets. This surface is created only if a client requests it via
+ * {@link #updateAndGetBoundsLayer(Transaction)}. By parenting to this bounds surface, child
+ * surfaces can ensure they do not draw into the surface inset region set by the parent window.
*/
private SurfaceControl mBoundsLayer;
private final SurfaceSession mSurfaceSession = new SurfaceSession();
@@ -2261,7 +2261,7 @@
* <p>Parenting to this layer will ensure that its children are cropped by the view's surface
* insets.
*/
- public SurfaceControl getBoundsLayer() {
+ public SurfaceControl updateAndGetBoundsLayer(Transaction t) {
if (mBoundsLayer == null) {
mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
.setContainerLayer()
@@ -2269,8 +2269,8 @@
.setParent(getSurfaceControl())
.setCallsite("ViewRootImpl.getBoundsLayer")
.build();
- setBoundsLayerCrop(mTransaction);
- mTransaction.show(mBoundsLayer).apply();
+ setBoundsLayerCrop(t);
+ t.show(mBoundsLayer);
}
return mBoundsLayer;
}
@@ -11231,7 +11231,8 @@
@Nullable public SurfaceControl.Transaction buildReparentTransaction(
@NonNull SurfaceControl child) {
if (mSurfaceControl.isValid()) {
- return new SurfaceControl.Transaction().reparent(child, getBoundsLayer());
+ Transaction t = new Transaction();
+ return t.reparent(child, updateAndGetBoundsLayer(t));
}
return null;
}
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index afc567e..c88048c 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -97,6 +97,12 @@
*/
String EXTRA_START_REASON = "android.intent.extra.EXTRA_START_REASON";
+ /**
+ * Set to {@code true} when intent was invoked from pressing one of the brightness keys.
+ * @hide
+ */
+ String EXTRA_FROM_BRIGHTNESS_KEY = "android.intent.extra.FROM_BRIGHTNESS_KEY";
+
// TODO: move this to a more appropriate place.
interface PointerEventListener {
/**
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index e098b63..a43906f 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -192,6 +192,8 @@
* <li>{@link #getEventTime()} - The event time.</li>
* <li>{@link #getScrollDeltaX()} - The difference in the horizontal position.</li>
* <li>{@link #getScrollDeltaY()} - The difference in the vertical position.</li>
+ * <li>{@link #getMaxScrollX()} ()} - The max scroll offset of the source left edge</li>
+ * <li>{@link #getMaxScrollY()} ()} - The max scroll offset of the source top edge.</li>
* </ul>
* </p>
* <p>
@@ -538,8 +540,18 @@
public static final int TYPE_WINDOW_CONTENT_CHANGED = 1 << 11;
/**
- * Represents the event of scrolling a view. This event type is generally not sent directly.
- * @see android.view.View#onScrollChanged(int, int, int, int)
+ * Represents the event of scrolling a view. This event type is generally not sent directly. In
+ * the View system, this is sent in
+ * {@link android.view.View#onScrollChanged(int, int, int, int)}
+ * <p>In addition to the source and package name, the event should populate scroll-specific
+ * properties like {@link #setScrollDeltaX(int)}, {@link #setScrollDeltaY(int)},
+ * {@link #setMaxScrollX(int)}, and {@link #setMaxScrollY(int)}.
+ * <p>Services are encouraged to rely on the source to query UI state over AccessibilityEvents
+ * properties. For example, to check after a scroll if the bottom of the scrolling UI element
+ * has been reached, check if the source node is scrollable and has the
+ * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_SCROLL_BACKWARD} action but not the
+ * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_SCROLL_FORWARD} action.
+ * For scrolling to a target, use {@link #TYPE_VIEW_TARGETED_BY_SCROLL}.
*/
public static final int TYPE_VIEW_SCROLLED = 1 << 12;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 2939954..e6a8b78 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -425,11 +425,13 @@
/**
* Action to scroll the node content forward.
+ * @see AccessibilityAction#ACTION_SCROLL_FORWARD
*/
public static final int ACTION_SCROLL_FORWARD = 1 << 12;
/**
* Action to scroll the node content backward.
+ * @see AccessibilityAction#ACTION_SCROLL_BACKWARD
*/
public static final int ACTION_SCROLL_BACKWARD = 1 << 13;
@@ -5404,6 +5406,42 @@
* <strong>Arguments:</strong>
* {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT}. This is an optional argument.
* </p>
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. Depending on the orientation,
+ * this element should also add the relevant directional scroll actions of
+ * {@link #ACTION_SCROLL_LEFT}, {@link #ACTION_SCROLL_RIGHT},
+ * {@link #ACTION_SCROLL_UP}, and {@link #ACTION_SCROLL_DOWN}. If the scrolling brings
+ * the next or previous element into view as the center element, such as in a ViewPager2,
+ * use {@link #ACTION_PAGE_DOWN} and the other page actions instead of the directional
+ * actions.
+ * <p>Example: a scrolling UI of vertical orientation with a forward
+ * scroll action should also add the scroll down action:
+ * <pre class="prettyprint"><code>
+ * onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ * super.onInitializeAccessibilityNodeInfo(info);
+ * if (canScrollForward) {
+ * info.addAction(ACTION_SCROLL_FORWARD);
+ * info.addAction(ACTION_SCROLL_DOWN);
+ * }
+ * }
+ * performAccessibilityAction(int action, Bundle bundle) {
+ * if (action == ACTION_SCROLL_FORWARD || action == ACTION_SCROLL_DOWN) {
+ * scrollForward();
+ * }
+ * }
+ * scrollForward() {
+ * ...
+ * if (mAccessibilityManager.isEnabled()) {
+ * event = new AccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
+ * event.setScrollDeltaX(dx);
+ * event.setScrollDeltaY(dy);
+ * event.setMaxScrollX(maxDx);
+ * event.setMaxScrollY(maxDY);
+ * sendAccessibilityEventUnchecked(event);
+ * }
+ * }
+ * </code>
+ * </pre></p>
*/
public static final AccessibilityAction ACTION_SCROLL_FORWARD =
new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
@@ -5414,6 +5452,54 @@
* <strong>Arguments:</strong>
* {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT}. This is an optional argument.
* </p>
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. Depending on the orientation,
+ * this element should also add the relevant directional scroll actions of
+ * {@link #ACTION_SCROLL_LEFT}, {@link #ACTION_SCROLL_RIGHT},
+ * {@link #ACTION_SCROLL_UP}, and {@link #ACTION_SCROLL_DOWN}. If the scrolling brings
+ * the next or previous element into view as the center element, such as in a ViewPager2,
+ * use {@link #ACTION_PAGE_DOWN} and the other page actions instead of the directional
+ * actions.
+ * <p> Example: a scrolling UI of horizontal orientation with a backward
+ * scroll action should also add the scroll left/right action (LTR/RTL):
+ * <pre class="prettyprint"><code>
+ * onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ * super.onInitializeAccessibilityNodeInfo(info);
+ * if (canScrollBackward) {
+ * info.addAction(ACTION_SCROLL_FORWARD);
+ * if (leftToRight) {
+ * info.addAction(ACTION_SCROLL_LEFT);
+ * } else {
+ * info.addAction(ACTION_SCROLL_RIGHT);
+ * }
+ * }
+ * }
+ * performAccessibilityAction(int action, Bundle bundle) {
+ * if (action == ACTION_SCROLL_BACKWARD) {
+ * scrollBackward();
+ * } else if (action == ACTION_SCROLL_LEFT) {
+ * if (!isRTL()){
+ * scrollBackward();
+ * }
+ * } else if (action == ACTION_SCROLL_RIGHT) {
+ * if (isRTL()){
+ * scrollBackward();
+ * }
+ * }
+ * }
+ * scrollBackward() {
+ * ...
+ * if (mAccessibilityManager.isEnabled()) {
+ * event = new AccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
+ * event.setScrollDeltaX(dx);
+ * event.setScrollDeltaY(dy);
+ * event.setMaxScrollX(maxDx);
+ * event.setMaxScrollY(maxDY);
+ * sendAccessibilityEventUnchecked(event);
+ * }
+ * }
+ * </code>
+ * </pre></p>
*/
public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
@@ -5509,6 +5595,8 @@
/**
* Action that requests the node make its bounding rectangle visible
* on the screen, scrolling if necessary just enough.
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*
* @see View#requestRectangleOnScreen(Rect)
*/
@@ -5524,6 +5612,8 @@
* <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li>
* <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li>
* <ul>
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*
* @see AccessibilityNodeInfo#getCollectionInfo()
*/
@@ -5562,6 +5652,8 @@
* <strong>Arguments:</strong>
* {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT}. This is an optional argument.
* </p>
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_SCROLL_UP =
new AccessibilityAction(R.id.accessibilityActionScrollUp);
@@ -5572,6 +5664,8 @@
* <strong>Arguments:</strong>
* {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT}. This is an optional argument.
* </p>
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_SCROLL_LEFT =
new AccessibilityAction(R.id.accessibilityActionScrollLeft);
@@ -5582,6 +5676,8 @@
* <strong>Arguments:</strong>
* {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT}. This is an optional argument.
* </p>
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_SCROLL_DOWN =
new AccessibilityAction(R.id.accessibilityActionScrollDown);
@@ -5592,30 +5688,40 @@
* <strong>Arguments:</strong>
* {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT}. This is an optional argument.
* </p>
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_SCROLL_RIGHT =
new AccessibilityAction(R.id.accessibilityActionScrollRight);
/**
* Action to move to the page above.
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_PAGE_UP =
new AccessibilityAction(R.id.accessibilityActionPageUp);
/**
* Action to move to the page below.
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_PAGE_DOWN =
new AccessibilityAction(R.id.accessibilityActionPageDown);
/**
* Action to move to the page left.
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_PAGE_LEFT =
new AccessibilityAction(R.id.accessibilityActionPageLeft);
/**
* Action to move to the page right.
+ * <p>The UI element that implements this should send a
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
*/
public static final AccessibilityAction ACTION_PAGE_RIGHT =
new AccessibilityAction(R.id.accessibilityActionPageRight);
@@ -5720,8 +5826,9 @@
* This action initiates a drag & drop within the system. The source's dragged content is
* prepared before the drag begins. In View, this action should prepare the arguments to
* {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} and then
- * call {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)}. The
- * equivalent should be performed for other UI toolkits.
+ * call {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} with
+ * {@link View#DRAG_FLAG_ACCESSIBILITY_ACTION}. The equivalent should be performed for other
+ * UI toolkits.
* </p>
*
* @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED
@@ -5735,7 +5842,8 @@
* This action is added to potential drop targets if the source started a drag with
* {@link #ACTION_DRAG_START}. In View, these targets are Views that accepted
* {@link android.view.DragEvent#ACTION_DRAG_STARTED} and have an
- * {@link View.OnDragListener}.
+ * {@link View.OnDragListener}, and the drop occurs at the center location of the View's
+ * window bounds.
* </p>
*
* @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
index adfeb6d..21b4334 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
@@ -57,8 +57,9 @@
*
* @param displayId The logical display id.
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ * @param updatePersistence whether the new scale should be persisted in Settings
*/
- void onPerformScaleAction(int displayId, float scale);
+ void onPerformScaleAction(int displayId, float scale, boolean updatePersistence);
/**
* Called when the accessibility action is performed.
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index c9afdc0..2c7d326 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -414,7 +414,7 @@
/** @hide */
public static final boolean DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER = false;
/** @hide */
- public static final int DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE = 1000;
+ public static final int DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE = 5000;
/** @hide */
public static final int DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE = 150;
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index f0d1019..03d1cd8 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -16,8 +16,12 @@
package android.view.inputmethod;
+import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
+import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
+
import static com.android.internal.inputmethod.InputMethodDebug.softInputDisplayReasonToString;
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_IME_INSETS_ANIMATION;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_IME_INSETS_HIDE_ANIMATION;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_IME_INSETS_SHOW_ANIMATION;
import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_HIDDEN;
import static com.android.internal.util.LatencyTracker.ACTION_REQUEST_IME_SHOWN;
@@ -696,20 +700,22 @@
/**
* Called when the animation, which is going to be monitored, starts.
*
- * @param jankContext context which is needed by {@link InteractionJankMonitor}
- * @param animType {@link AnimationType}
+ * @param jankContext context which is needed by {@link InteractionJankMonitor}.
+ * @param animType the animation type.
* @param useSeparatedThread {@code true} if the animation is handled by the app,
* {@code false} if the animation will be scheduled on the
- * {@link android.view.InsetsAnimationThread}
+ * {@link android.view.InsetsAnimationThread}.
*/
public void onRequestAnimation(@NonNull InputMethodJankContext jankContext,
@AnimationType int animType, boolean useSeparatedThread) {
+ final int cujType = getImeInsetsCujFromAnimation(animType);
if (jankContext.getDisplayContext() == null
- || jankContext.getTargetSurfaceControl() == null) {
+ || jankContext.getTargetSurfaceControl() == null
+ || cujType == -1) {
return;
}
final Configuration.Builder builder = Configuration.Builder.withSurface(
- CUJ_IME_INSETS_ANIMATION,
+ cujType,
jankContext.getDisplayContext(),
jankContext.getTargetSurfaceControl())
.setTag(String.format(Locale.US, "%d@%d@%s", animType,
@@ -719,16 +725,44 @@
/**
* Called when the animation, which is going to be monitored, cancels.
+ *
+ * @param animType the animation type.
*/
- public void onCancelAnimation() {
- InteractionJankMonitor.getInstance().cancel(CUJ_IME_INSETS_ANIMATION);
+ public void onCancelAnimation(@AnimationType int animType) {
+ final int cujType = getImeInsetsCujFromAnimation(animType);
+ if (cujType == -1) {
+ InteractionJankMonitor.getInstance().cancel(cujType);
+ }
}
/**
* Called when the animation, which is going to be monitored, ends.
+ *
+ * @param animType the animation type.
*/
- public void onFinishAnimation() {
- InteractionJankMonitor.getInstance().end(CUJ_IME_INSETS_ANIMATION);
+ public void onFinishAnimation(@AnimationType int animType) {
+ final int cujType = getImeInsetsCujFromAnimation(animType);
+ if (cujType != -1) {
+ InteractionJankMonitor.getInstance().end(cujType);
+ }
+ }
+
+ /**
+ * A helper method to translate animation type to CUJ type for IME animations.
+ *
+ * @param animType the animation type.
+ * @return the integer in {@link com.android.internal.jank.InteractionJankMonitor.CujType},
+ * or {@code -1} if the animation type is not supported for tracking yet.
+ */
+ private static int getImeInsetsCujFromAnimation(@AnimationType int animType) {
+ switch (animType) {
+ case ANIMATION_TYPE_SHOW:
+ return CUJ_IME_INSETS_SHOW_ANIMATION;
+ case ANIMATION_TYPE_HIDE:
+ return CUJ_IME_INSETS_HIDE_ANIMATION;
+ default:
+ return -1;
+ }
}
}
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index efe3fd4..a67d839 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -31,6 +31,7 @@
import android.view.ContextMenu.ContextMenuInfo;
import android.view.SoundEffectConstants;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ExpandableListConnector.PositionMetadata;
@@ -660,7 +661,11 @@
// Internally handle the item click
final int adjustedPosition = getFlatPositionForConnector(position);
- return handleItemClick(v, adjustedPosition, id);
+ final boolean clicked = handleItemClick(v, adjustedPosition, id);
+ if (v != null) {
+ v.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+ }
+ return clicked;
}
/**
@@ -1150,13 +1155,16 @@
public void onInitializeAccessibilityNodeInfoForItem(
View view, int position, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoForItem(view, position, info);
-
final PositionMetadata metadata = mConnector.getUnflattenedPos(position);
if (metadata.position.type == ExpandableListPosition.GROUP) {
- if (isGroupExpanded(metadata.position.groupPos)) {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
- } else {
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+ if (view != null && view.isEnabled()) {
+ info.setClickable(true);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
+ if (isGroupExpanded(metadata.position.groupPos)) {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
+ } else {
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+ }
}
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index b65c1a1..cb5dbe6 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1550,6 +1550,7 @@
float deltaDistance = -unconsumed * FLING_DESTRETCH_FACTOR / size;
int consumed = Math.round(-size / FLING_DESTRETCH_FACTOR
* mEdgeGlowTop.onPullDistance(deltaDistance, 0.5f));
+ mEdgeGlowTop.onRelease();
if (consumed != unconsumed) {
mEdgeGlowTop.finish();
}
@@ -1560,6 +1561,7 @@
float deltaDistance = unconsumed * FLING_DESTRETCH_FACTOR / size;
int consumed = Math.round(size / FLING_DESTRETCH_FACTOR
* mEdgeGlowBottom.onPullDistance(deltaDistance, 0.5f));
+ mEdgeGlowBottom.onRelease();
if (consumed != unconsumed) {
mEdgeGlowBottom.finish();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index cc50f79..56349d1 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6938,12 +6938,26 @@
* parameters used to create the PrecomputedText mismatches
* with this TextView.
*/
- @android.view.RemotableViewMethod
+ @android.view.RemotableViewMethod(asyncImpl = "setTextAsync")
public final void setText(CharSequence text) {
setText(text, mBufferType);
}
/**
+ * RemotableViewMethod's asyncImpl of {@link #setText(CharSequence)}.
+ * This should be called on a background thread, and returns a Runnable which is then must be
+ * called on the main thread to complete the operation and set text.
+ * @param text text to be displayed
+ * @return Runnable that sets text; must be called on the main thread by the caller of this
+ * method to complete the operation
+ * @hide
+ */
+ @NonNull
+ public Runnable setTextAsync(@Nullable CharSequence text) {
+ return () -> setText(text);
+ }
+
+ /**
* Sets the text to be displayed but retains the cursor position. Same as
* {@link #setText(CharSequence)} except that the cursor position (if any) is retained in the
* new text.
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 9f804b1..3323ae5 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -688,6 +688,7 @@
.setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type)
.setSource(InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE)
.setArbitraryRectangle(frame))
+ .setInsetsFrameOwner(owner)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
@@ -712,6 +713,7 @@
new HierarchyOp.Builder(HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER)
.setContainer(receiver.asBinder())
.setInsetsFrameProvider(new InsetsFrameProvider(owner, index, type))
+ .setInsetsFrameOwner(owner)
.build();
mHierarchyOps.add(hierarchyOp);
return this;
@@ -1344,8 +1346,12 @@
@Nullable
private IBinder mReparent;
+ @Nullable
private InsetsFrameProvider mInsetsFrameProvider;
+ @Nullable
+ private IBinder mInsetsFrameOwner;
+
// Moves/reparents to top of parent when {@code true}, otherwise moves/reparents to bottom.
private boolean mToTop;
@@ -1478,6 +1484,7 @@
mContainer = copy.mContainer;
mReparent = copy.mReparent;
mInsetsFrameProvider = copy.mInsetsFrameProvider;
+ mInsetsFrameOwner = copy.mInsetsFrameOwner;
mToTop = copy.mToTop;
mReparentTopOnly = copy.mReparentTopOnly;
mWindowingModes = copy.mWindowingModes;
@@ -1496,6 +1503,7 @@
mContainer = in.readStrongBinder();
mReparent = in.readStrongBinder();
mInsetsFrameProvider = in.readTypedObject(InsetsFrameProvider.CREATOR);
+ mInsetsFrameOwner = in.readStrongBinder();
mToTop = in.readBoolean();
mReparentTopOnly = in.readBoolean();
mWindowingModes = in.createIntArray();
@@ -1527,6 +1535,11 @@
return mInsetsFrameProvider;
}
+ @Nullable
+ public IBinder getInsetsFrameOwner() {
+ return mInsetsFrameOwner;
+ }
+
@NonNull
public IBinder getContainer() {
return mContainer;
@@ -1657,7 +1670,8 @@
case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER:
case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER:
sb.append("container=").append(mContainer)
- .append(" provider=").append(mInsetsFrameProvider);
+ .append(" provider=").append(mInsetsFrameProvider)
+ .append(" owner=").append(mInsetsFrameOwner);
break;
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
sb.append("container=").append(mContainer)
@@ -1697,6 +1711,7 @@
dest.writeStrongBinder(mContainer);
dest.writeStrongBinder(mReparent);
dest.writeTypedObject(mInsetsFrameProvider, flags);
+ dest.writeStrongBinder(mInsetsFrameOwner);
dest.writeBoolean(mToTop);
dest.writeBoolean(mReparentTopOnly);
dest.writeIntArray(mWindowingModes);
@@ -1737,8 +1752,12 @@
@Nullable
private IBinder mReparent;
+ @Nullable
private InsetsFrameProvider mInsetsFrameProvider;
+ @Nullable
+ private IBinder mInsetsFrameOwner;
+
private boolean mToTop;
private boolean mReparentTopOnly;
@@ -1782,8 +1801,13 @@
return this;
}
- Builder setInsetsFrameProvider(InsetsFrameProvider providers) {
- mInsetsFrameProvider = providers;
+ Builder setInsetsFrameProvider(InsetsFrameProvider provider) {
+ mInsetsFrameProvider = provider;
+ return this;
+ }
+
+ Builder setInsetsFrameOwner(IBinder owner) {
+ mInsetsFrameOwner = owner;
return this;
}
@@ -1854,6 +1878,7 @@
? Arrays.copyOf(mActivityTypes, mActivityTypes.length)
: null;
hierarchyOp.mInsetsFrameProvider = mInsetsFrameProvider;
+ hierarchyOp.mInsetsFrameOwner = mInsetsFrameOwner;
hierarchyOp.mToTop = mToTop;
hierarchyOp.mReparentTopOnly = mReparentTopOnly;
hierarchyOp.mLaunchOptions = mLaunchOptions;
diff --git a/core/java/android/window/WindowInfosListenerForTest.java b/core/java/android/window/WindowInfosListenerForTest.java
index 7fc55a7..bdbce13 100644
--- a/core/java/android/window/WindowInfosListenerForTest.java
+++ b/core/java/android/window/WindowInfosListenerForTest.java
@@ -90,7 +90,8 @@
@Override
public String toString() {
- return name + ", frame=" + bounds
+ return name + ", displayId=" + displayId
+ + ", frame=" + bounds
+ ", isVisible=" + isVisible
+ ", isTrustedOverlay=" + isTrustedOverlay
+ ", token=" + windowToken;
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 6b8ae94..81cd280 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -84,11 +84,14 @@
/** Gating the holding of WakeLocks until NLSes are told about a new notification. */
public static final Flag WAKE_LOCK_FOR_POSTING_NOTIFICATION =
- devFlag("persist.sysui.notification.wake_lock_for_posting_notification");
+ releasedFlag("persist.sysui.notification.wake_lock_for_posting_notification");
/** Gating storing NotificationRankingUpdate ranking map in shared memory. */
public static final Flag RANKING_UPDATE_ASHMEM = devFlag(
"persist.sysui.notification.ranking_update_ashmem");
+
+ public static final Flag PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS = devFlag(
+ "persist.sysui.notification.propagate_channel_updates_to_conversations");
}
//// == End of flags. Everything below this line is the implementation. == ////
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index d78689e9..b7a2c71 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -95,7 +95,7 @@
@UnsupportedAppUsage
public void register(Context context, Looper thread, UserHandle user,
boolean externalStorage) {
- register(context, user, externalStorage,
+ register(context, user,
(thread == null) ? BackgroundThread.getHandler() : new Handler(thread));
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 92427ec..03d7450 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -25,7 +25,8 @@
import static com.android.internal.jank.FrameTracker.REASON_END_NORMAL;
import static com.android.internal.jank.FrameTracker.REASON_END_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BIOMETRIC_PROMPT_TRANSITION;
-import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_SHOW_ANIMATION;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
@@ -257,7 +258,6 @@
public static final int CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS = 66;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE = 67;
public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME = 68;
- public static final int CUJ_IME_INSETS_ANIMATION = 69;
public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70;
public static final int CUJ_LAUNCHER_OPEN_SEARCH_RESULT = 71;
// 72 - 77 are reserved for b/281564325.
@@ -269,8 +269,10 @@
*/
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78;
public static final int CUJ_SHADE_EXPAND_FROM_STATUS_BAR = 79;
+ public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80;
+ public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81;
- private static final int LAST_CUJ = CUJ_SHADE_EXPAND_FROM_STATUS_BAR;
+ private static final int LAST_CUJ = CUJ_IME_INSETS_HIDE_ANIMATION;
private static final int NO_STATSD_LOGGING = -1;
// Used to convert CujType to InteractionType enum value for statsd logging.
@@ -348,7 +350,7 @@
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_SWIPE_TO_RECENTS;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_SWIPE;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_TO_HOME;
- CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION;
+ CUJ_TO_STATSD_INTERACTION_TYPE[69] = NO_STATSD_LOGGING; // This is deprecated.
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_OPEN_SEARCH_RESULT] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_SEARCH_RESULT;
// 72 - 77 are reserved for b/281564325.
@@ -360,6 +362,8 @@
CUJ_TO_STATSD_INTERACTION_TYPE[77] = NO_STATSD_LOGGING;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_EXPAND_FROM_STATUS_BAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_SHOW_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_SHOW_ANIMATION;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_HIDE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION;
}
private static class InstanceHolder {
@@ -456,11 +460,12 @@
CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE,
CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME,
- CUJ_IME_INSETS_ANIMATION,
CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION,
CUJ_LAUNCHER_OPEN_SEARCH_RESULT,
CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK,
CUJ_SHADE_EXPAND_FROM_STATUS_BAR,
+ CUJ_IME_INSETS_SHOW_ANIMATION,
+ CUJ_IME_INSETS_HIDE_ANIMATION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -1066,8 +1071,6 @@
return "LAUNCHER_CLOSE_ALL_APPS_SWIPE";
case CUJ_LAUNCHER_CLOSE_ALL_APPS_TO_HOME:
return "LAUNCHER_CLOSE_ALL_APPS_TO_HOME";
- case CUJ_IME_INSETS_ANIMATION:
- return "IME_INSETS_ANIMATION";
case CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION:
return "LOCKSCREEN_CLOCK_MOVE_ANIMATION";
case CUJ_LAUNCHER_OPEN_SEARCH_RESULT:
@@ -1076,6 +1079,10 @@
return "LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK";
case CUJ_SHADE_EXPAND_FROM_STATUS_BAR:
return "SHADE_EXPAND_FROM_STATUS_BAR";
+ case CUJ_IME_INSETS_SHOW_ANIMATION:
+ return "IME_INSETS_SHOW_ANIMATION";
+ case CUJ_IME_INSETS_HIDE_ANIMATION:
+ return "IME_INSETS_HIDE_ANIMATION";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 2063542..0c6d6f9 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -195,6 +195,11 @@
*/
public static final int PROFILEABLE = 1 << 24;
+ /**
+ * Enable ptrace. This is enabled on eng or userdebug builds, or if the app is debuggable.
+ */
+ public static final int DEBUG_ENABLE_PTRACE = 1 << 25;
+
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
/** Default external storage should be mounted. */
@@ -1028,6 +1033,9 @@
if (Build.IS_ENG || ENABLE_JDWP) {
args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
}
+ if (RoSystemProperties.DEBUGGABLE) {
+ args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_PTRACE;
+ }
}
/**
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 1ac5e1f..de10bd2 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.os.Trace;
import android.text.BoringLayout;
import android.text.Layout;
import android.text.StaticLayout;
@@ -68,6 +69,7 @@
protected Layout makeSingleLayout(int wantWidth, BoringLayout.Metrics boring, int ellipsisWidth,
Layout.Alignment alignment, boolean shouldEllipsize,
TextUtils.TruncateAt effectiveEllipsize, boolean useSaved) {
+ Trace.beginSection("ImageFloatingTextView#makeSingleLayout");
TransformationMethod transformationMethod = getTransformationMethod();
CharSequence text = getText();
if (transformationMethod != null) {
@@ -110,7 +112,9 @@
builder.setIndents(null, margins);
}
- return builder.build();
+ final StaticLayout result = builder.build();
+ Trace.endSection();
+ return result;
}
/**
@@ -135,6 +139,7 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ Trace.beginSection("ImageFloatingTextView#onMeasure");
int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mPaddingTop - mPaddingBottom;
if (getLayout() != null && getLayout().getHeight() != availableHeight) {
// We've been measured before and the new size is different than before, lets make sure
@@ -161,6 +166,7 @@
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
+ Trace.endSection();
}
@Override
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index 65e5e29..c88763c 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -64,9 +64,9 @@
// is represented as a byte array of length 0.
private byte[] mCredential;
- // This indicates that the credential is a password that used characters outside ASCII 32–127.
+ // This indicates that the credential used characters outside ASCII 32–127.
//
- // Such passwords were never intended to be allowed. However, Android 10–14 had a bug where
+ // Such credentials were never intended to be allowed. However, Android 10–14 had a bug where
// conversion from the chars the user entered to the credential bytes used a simple truncation.
// Thus, any 'char' whose remainder mod 256 was in the range 32–127 was accepted and was
// equivalent to some ASCII character. For example, ™, which is U+2122, was truncated to ASCII
@@ -102,7 +102,6 @@
// LockscreenCredential object to be constructed so that the validation logic can run,
// even though the validation logic will ultimately reject the credential as too short.
}
- Preconditions.checkArgument(!hasInvalidChars || type == CREDENTIAL_TYPE_PASSWORD);
mType = type;
mCredential = credential;
mHasInvalidChars = hasInvalidChars;
@@ -262,6 +261,9 @@
* short
*/
public void validateBasicRequirements() {
+ if (mHasInvalidChars) {
+ throw new IllegalArgumentException("credential contains invalid characters");
+ }
switch (getType()) {
case CREDENTIAL_TYPE_PATTERN:
if (size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
@@ -276,9 +278,6 @@
}
break;
case CREDENTIAL_TYPE_PASSWORD:
- if (mHasInvalidChars) {
- throw new IllegalArgumentException("password contains invalid characters");
- }
if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) {
throw new IllegalArgumentException("password must be at least "
+ LockPatternUtils.MIN_LOCK_PASSWORD_SIZE + " characters long.");
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index e1be0cd..0b51a41 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -30,6 +30,8 @@
#include <media/AudioSystem.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/jni_macros.h>
#include <system/audio.h>
#include <system/audio_policy.h>
#include <utils/Log.h>
@@ -285,7 +287,7 @@
ALOGE("Can't find class %s", kEventHandlerClassPathName);
return;
}
- mClass = (jclass)env->NewGlobalRef(clazz);
+ mClass = static_cast<jclass>(env->NewGlobalRef(clazz));
// We use a weak reference so the AudioPortEventHandler object can be garbage collected.
// The reference is only used as a proxy for callbacks.
@@ -337,15 +339,16 @@
const sp<JNIAudioPortCallback>& callback)
{
Mutex::Autolock l(gLock);
- sp<JNIAudioPortCallback> old =
- (JNIAudioPortCallback*)env->GetLongField(thiz, gEventHandlerFields.mJniCallback);
+ sp<JNIAudioPortCallback> old = reinterpret_cast<JNIAudioPortCallback *>(
+ env->GetLongField(thiz, gEventHandlerFields.mJniCallback));
if (callback.get()) {
- callback->incStrong((void*)setJniCallback);
+ callback->incStrong(reinterpret_cast<void *>(setJniCallback));
}
if (old != 0) {
- old->decStrong((void*)setJniCallback);
+ old->decStrong(reinterpret_cast<void *>(setJniCallback));
}
- env->SetLongField(thiz, gEventHandlerFields.mJniCallback, (jlong)callback.get());
+ env->SetLongField(thiz, gEventHandlerFields.mJniCallback,
+ reinterpret_cast<jlong>(callback.get()));
return old;
}
@@ -374,43 +377,44 @@
jobjectArray deviceAddresses,
AudioDeviceTypeAddrVector &audioDeviceTypeAddrVector) {
if (deviceTypes == nullptr || deviceAddresses == nullptr) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
jsize deviceCount = env->GetArrayLength(deviceTypes);
if (deviceCount == 0 || deviceCount != env->GetArrayLength(deviceAddresses)) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
// retrieve all device types
std::vector<audio_devices_t> deviceTypesVector;
jint *typesPtr = nullptr;
typesPtr = env->GetIntArrayElements(deviceTypes, 0);
if (typesPtr == nullptr) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
for (jint i = 0; i < deviceCount; i++) {
- deviceTypesVector.push_back((audio_devices_t)typesPtr[i]);
+ deviceTypesVector.push_back(static_cast<audio_devices_t>(typesPtr[i]));
}
// check each address is a string and add device type/address to list
jclass stringClass = FindClassOrDie(env, "java/lang/String");
for (jint i = 0; i < deviceCount; i++) {
jobject addrJobj = env->GetObjectArrayElement(deviceAddresses, i);
if (!env->IsInstanceOf(addrJobj, stringClass)) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
- const char *address = env->GetStringUTFChars((jstring)addrJobj, NULL);
- AudioDeviceTypeAddr dev = AudioDeviceTypeAddr((audio_devices_t)typesPtr[i], address);
+ const char *address = env->GetStringUTFChars(static_cast<jstring>(addrJobj), NULL);
+ AudioDeviceTypeAddr dev =
+ AudioDeviceTypeAddr(static_cast<audio_devices_t>(typesPtr[i]), address);
audioDeviceTypeAddrVector.push_back(dev);
- env->ReleaseStringUTFChars((jstring)addrJobj, address);
+ env->ReleaseStringUTFChars(static_cast<jstring>(addrJobj), address);
}
env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);
- return (jint)NO_ERROR;
+ return NO_ERROR;
}
static jint
android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
{
- return (jint) check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
+ return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
}
static jboolean
@@ -425,7 +429,7 @@
android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
{
bool state = false;
- AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
+ AudioSystem::isStreamActive(static_cast<audio_stream_type_t>(stream), &state, inPastMs);
return state;
}
@@ -434,7 +438,7 @@
jint inPastMs)
{
bool state = false;
- AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
+ AudioSystem::isStreamActiveRemotely(static_cast<audio_stream_type_t>(stream), &state, inPastMs);
return state;
}
@@ -442,7 +446,7 @@
android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
{
bool state = false;
- AudioSystem::isSourceActive((audio_source_t) source, &state);
+ AudioSystem::isSourceActive(static_cast<audio_source_t>(source), &state);
return state;
}
@@ -478,7 +482,7 @@
env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
}
int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
- return (jint) status;
+ return status;
}
static jstring
@@ -558,15 +562,15 @@
return;
}
jint recParamData[REC_PARAM_SIZE];
- recParamData[0] = (jint) audioFormatFromNative(clientConfig->format);
+ recParamData[0] = audioFormatFromNative(clientConfig->format);
// FIXME this doesn't support index-based masks
- recParamData[1] = (jint) inChannelMaskFromNative(clientConfig->channel_mask);
- recParamData[2] = (jint) clientConfig->sample_rate;
- recParamData[3] = (jint) audioFormatFromNative(deviceConfig->format);
+ recParamData[1] = inChannelMaskFromNative(clientConfig->channel_mask);
+ recParamData[2] = clientConfig->sample_rate;
+ recParamData[3] = audioFormatFromNative(deviceConfig->format);
// FIXME this doesn't support index-based masks
- recParamData[4] = (jint) inChannelMaskFromNative(deviceConfig->channel_mask);
- recParamData[5] = (jint) deviceConfig->sample_rate;
- recParamData[6] = (jint) patchHandle;
+ recParamData[4] = inChannelMaskFromNative(deviceConfig->channel_mask);
+ recParamData[5] = deviceConfig->sample_rate;
+ recParamData[6] = patchHandle;
env->SetIntArrayRegion(recParamArray, 0, REC_PARAM_SIZE, recParamData);
jobjectArray jClientEffects;
@@ -580,10 +584,9 @@
env->CallStaticVoidMethod(clazz,
gAudioPolicyEventHandlerMethods.postRecordConfigEventFromNative,
- event, (jint) clientInfo->riid, (jint) clientInfo->uid,
- clientInfo->session, clientInfo->source, clientInfo->port_id,
- clientInfo->silenced, recParamArray, jClientEffects, jEffects,
- source);
+ event, clientInfo->riid, clientInfo->uid, clientInfo->session,
+ clientInfo->source, clientInfo->port_id, clientInfo->silenced,
+ recParamArray, jClientEffects, jEffects, source);
env->DeleteLocalRef(clazz);
env->DeleteLocalRef(recParamArray);
env->DeleteLocalRef(jClientEffects);
@@ -626,11 +629,9 @@
if (Parcel *parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
android::media::audio::common::AudioPort port{};
if (status_t statusOfParcel = port.readFromParcel(parcel); statusOfParcel == OK) {
- status = check_AudioSystem_Command(
- AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(
- state),
- port,
- static_cast<audio_format_t>(codec)));
+ status = check_AudioSystem_Command(
+ AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(state),
+ port, static_cast<audio_format_t>(codec)));
} else {
ALOGE("Failed to read from parcel: %s", statusToString(statusOfParcel).c_str());
status = kAudioStatusError;
@@ -639,17 +640,17 @@
ALOGE("Failed to retrieve the native parcel from Java parcel");
status = kAudioStatusError;
}
- return (jint) status;
+ return status;
}
static jint
android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
{
const char *c_address = env->GetStringUTFChars(device_address, NULL);
- int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
- c_address));
+ int state = static_cast<int>(
+ AudioSystem::getDeviceConnectionState(static_cast<audio_devices_t>(device), c_address));
env->ReleaseStringUTFChars(device_address, c_address);
- return (jint) state;
+ return state;
}
static jint
@@ -658,38 +659,41 @@
{
const char *c_address = env->GetStringUTFChars(device_address, NULL);
const char *c_name = env->GetStringUTFChars(device_name, NULL);
- int status = check_AudioSystem_Command(AudioSystem::handleDeviceConfigChange(static_cast <audio_devices_t>(device),
- c_address, c_name, static_cast <audio_format_t>(codec)));
+ int status = check_AudioSystem_Command(
+ AudioSystem::handleDeviceConfigChange(static_cast<audio_devices_t>(device), c_address,
+ c_name, static_cast<audio_format_t>(codec)));
env->ReleaseStringUTFChars(device_address, c_address);
env->ReleaseStringUTFChars(device_name, c_name);
- return (jint) status;
+ return status;
}
static jint android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state,
jint uid) {
- return (jint)check_AudioSystem_Command(
- AudioSystem::setPhoneState((audio_mode_t)state, (uid_t)uid));
+ return check_AudioSystem_Command(
+ AudioSystem::setPhoneState(static_cast<audio_mode_t>(state), static_cast<uid_t>(uid)));
}
static jint
android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
{
- return (jint) check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
- static_cast <audio_policy_forced_cfg_t>(config)));
+ return check_AudioSystem_Command(
+ AudioSystem::setForceUse(static_cast<audio_policy_force_use_t>(usage),
+ static_cast<audio_policy_forced_cfg_t>(config)));
}
static jint
android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
{
- return static_cast <jint>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
+ return static_cast<jint>(
+ AudioSystem::getForceUse(static_cast<audio_policy_force_use_t>(usage)));
}
static jint
android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
{
- return (jint) check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
- indexMin,
- indexMax));
+ return check_AudioSystem_Command(
+ AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(stream), indexMin,
+ indexMax));
}
static jint
@@ -699,10 +703,9 @@
jint index,
jint device)
{
- return (jint) check_AudioSystem_Command(
- AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
- index,
- (audio_devices_t)device));
+ return check_AudioSystem_Command(
+ AudioSystem::setStreamVolumeIndex(static_cast<audio_stream_type_t>(stream), index,
+ static_cast<audio_devices_t>(device)));
}
static jint
@@ -712,13 +715,11 @@
jint device)
{
int index;
- if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
- &index,
- (audio_devices_t)device)
- != NO_ERROR) {
+ if (AudioSystem::getStreamVolumeIndex(static_cast<audio_stream_type_t>(stream), &index,
+ static_cast<audio_devices_t>(device)) != NO_ERROR) {
index = -1;
}
- return (jint) index;
+ return index;
}
static jint
@@ -731,11 +732,12 @@
// read the AudioAttributes values
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
- return (jint) check_AudioSystem_Command(
- AudioSystem::setVolumeIndexForAttributes(*(paa.get()), index, (audio_devices_t)device));
+ return check_AudioSystem_Command(
+ AudioSystem::setVolumeIndexForAttributes(*(paa.get()), index,
+ static_cast<audio_devices_t>(device)));
}
static jint
@@ -747,15 +749,16 @@
// read the AudioAttributes values
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
int index;
- if (AudioSystem::getVolumeIndexForAttributes(*(paa.get()), index, (audio_devices_t)device)
- != NO_ERROR) {
+ if (AudioSystem::getVolumeIndexForAttributes(*(paa.get()), index,
+ static_cast<audio_devices_t>(device)) !=
+ NO_ERROR) {
index = -1;
}
- return (jint) index;
+ return index;
}
static jint
@@ -766,7 +769,7 @@
// read the AudioAttributes values
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
int index;
@@ -774,7 +777,7 @@
!= NO_ERROR) {
index = -1;
}
- return (jint) index;
+ return index;
}
static jint
@@ -785,7 +788,7 @@
// read the AudioAttributes values
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
int index;
@@ -793,13 +796,13 @@
!= NO_ERROR) {
index = -1;
}
- return (jint) index;
+ return index;
}
static jint
android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
{
- return (jint) check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
+ return check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
}
static jfloat
@@ -815,7 +818,7 @@
static jint
android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
{
- return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
+ return check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
}
static jboolean
@@ -831,7 +834,7 @@
static jint
android_media_AudioSystem_setMasterMono(JNIEnv *env, jobject thiz, jboolean mono)
{
- return (jint) check_AudioSystem_Command(AudioSystem::setMasterMono(mono));
+ return check_AudioSystem_Command(AudioSystem::setMasterMono(mono));
}
static jboolean
@@ -847,7 +850,7 @@
static jint
android_media_AudioSystem_setMasterBalance(JNIEnv *env, jobject thiz, jfloat balance)
{
- return (jint) check_AudioSystem_Command(AudioSystem::setMasterBalance(balance));
+ return check_AudioSystem_Command(AudioSystem::setMasterBalance(balance));
}
static jfloat
@@ -865,37 +868,37 @@
static jint
android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
{
- return (jint) AudioSystem::getPrimaryOutputSamplingRate();
+ return AudioSystem::getPrimaryOutputSamplingRate();
}
static jint
android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
{
- return (jint) AudioSystem::getPrimaryOutputFrameCount();
+ return AudioSystem::getPrimaryOutputFrameCount();
}
static jint
android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
{
uint32_t afLatency;
- if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
- != NO_ERROR) {
+ if (AudioSystem::getOutputLatency(&afLatency, static_cast<audio_stream_type_t>(stream)) !=
+ NO_ERROR) {
afLatency = -1;
}
- return (jint) afLatency;
+ return afLatency;
}
static jint
android_media_AudioSystem_setLowRamDevice(
JNIEnv *env, jobject clazz, jboolean isLowRamDevice, jlong totalMemory)
{
- return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice, (int64_t) totalMemory);
+ return AudioSystem::setLowRamDevice(isLowRamDevice, totalMemory);
}
static jint
android_media_AudioSystem_checkAudioFlinger(JNIEnv *env, jobject clazz)
{
- return (jint) check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
+ return check_AudioSystem_Command(AudioSystem::checkAudioFlinger());
}
static void android_media_AudioSystem_setAudioFlingerBinder(JNIEnv *env, jobject clazz,
@@ -909,8 +912,8 @@
bool useInMask)
{
nAudioGainConfig->index = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mIndex);
- nAudioGainConfig->mode =
- (audio_gain_mode_t)env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode);
+ nAudioGainConfig->mode = static_cast<audio_gain_mode_t>(
+ env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mMode));
ALOGV("convertAudioGainConfigToNative got gain index %d", nAudioGainConfig->index);
jint jMask = env->GetIntField(jAudioGainConfig, gAudioGainConfigFields.mChannelMask);
audio_channel_mask_t nMask;
@@ -924,8 +927,8 @@
nAudioGainConfig->channel_mask = nMask;
nAudioGainConfig->ramp_duration_ms = env->GetIntField(jAudioGainConfig,
gAudioGainConfigFields.mRampDurationMs);
- jintArray jValues = (jintArray)env->GetObjectField(jAudioGainConfig,
- gAudioGainConfigFields.mValues);
+ jintArray jValues = static_cast<jintArray>(
+ env->GetObjectField(jAudioGainConfig, gAudioGainConfigFields.mValues));
int *nValues = env->GetIntArrayElements(jValues, NULL);
size_t size = env->GetArrayLength(jValues);
memcpy(nAudioGainConfig->values, nValues, size * sizeof(int));
@@ -940,8 +943,8 @@
jobject jAudioPort = env->GetObjectField(jAudioPortConfig, gAudioPortConfigFields.mPort);
jobject jHandle = env->GetObjectField(jAudioPort, gAudioPortFields.mHandle);
nAudioPortConfig->id = env->GetIntField(jHandle, gAudioHandleFields.mId);
- nAudioPortConfig->role = (audio_port_role_t)env->GetIntField(jAudioPort,
- gAudioPortFields.mRole);
+ nAudioPortConfig->role =
+ static_cast<audio_port_role_t>(env->GetIntField(jAudioPort, gAudioPortFields.mRole));
if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
nAudioPortConfig->type = AUDIO_PORT_TYPE_DEVICE;
} else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
@@ -949,7 +952,7 @@
} else {
env->DeleteLocalRef(jAudioPort);
env->DeleteLocalRef(jHandle);
- return (jint)AUDIO_JAVA_ERROR;
+ return AUDIO_JAVA_ERROR;
}
ALOGV("convertAudioPortConfigToNative handle %d role %d type %d",
nAudioPortConfig->id, nAudioPortConfig->role, nAudioPortConfig->type);
@@ -1004,7 +1007,7 @@
}
env->DeleteLocalRef(jAudioPort);
env->DeleteLocalRef(jHandle);
- return (jint)AUDIO_JAVA_SUCCESS;
+ return AUDIO_JAVA_SUCCESS;
}
/**
@@ -1025,15 +1028,15 @@
}
// Supports AUDIO_PORT_TYPE_DEVICE only
if (nAudioPortConfig->type != AUDIO_PORT_TYPE_DEVICE) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
jobject jAudioDevicePort = env->GetObjectField(jAudioPortConfig,
gAudioPortConfigFields.mPort);
- nAudioPortConfig->ext.device.type =
- (audio_devices_t)env->GetIntField(jAudioDevicePort, gAudioPortFields.mType);
- jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioDevicePort,
- gAudioPortFields.mAddress);
+ nAudioPortConfig->ext.device.type = static_cast<audio_devices_t>(
+ env->GetIntField(jAudioDevicePort, gAudioPortFields.mType));
+ jstring jDeviceAddress =
+ static_cast<jstring>(env->GetObjectField(jAudioDevicePort, gAudioPortFields.mAddress));
const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
strncpy(nAudioPortConfig->ext.device.address,
nDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN - 1);
@@ -1043,45 +1046,41 @@
return jStatus;
}
-static jint convertAudioPortConfigFromNative(JNIEnv *env,
- jobject jAudioPort,
- jobject *jAudioPortConfig,
- const struct audio_port_config *nAudioPortConfig)
-{
- jint jStatus = AUDIO_JAVA_SUCCESS;
- jobject jAudioGainConfig = NULL;
- jobject jAudioGain = NULL;
+static jint convertAudioPortConfigFromNative(JNIEnv *env, ScopedLocalRef<jobject> *jAudioPort,
+ ScopedLocalRef<jobject> *jAudioPortConfig,
+ const struct audio_port_config *nAudioPortConfig) {
jintArray jGainValues;
bool audioportCreated = false;
ALOGV("convertAudioPortConfigFromNative jAudioPort %p", jAudioPort);
- if (jAudioPort == NULL) {
- jobject jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
- nAudioPortConfig->id);
+ if (*jAudioPort == nullptr) {
+ ScopedLocalRef<jobject> jHandle(env,
+ env->NewObject(gAudioHandleClass, gAudioHandleCstor,
+ nAudioPortConfig->id));
ALOGV("convertAudioPortConfigFromNative handle %d is a %s", nAudioPortConfig->id,
nAudioPortConfig->type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix");
if (jHandle == NULL) {
- return (jint)AUDIO_JAVA_ERROR;
+ return AUDIO_JAVA_ERROR;
}
// create placeholder port and port config objects with just the correct handle
// and configuration data. The actual AudioPortConfig objects will be
// constructed by java code with correct class type (device, mix etc...)
// and reference to AudioPort instance in this client
- jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor,
- jHandle, // handle
- 0, // role
- NULL, // name
- NULL, // samplingRates
- NULL, // channelMasks
- NULL, // channelIndexMasks
- NULL, // formats
- NULL); // gains
- env->DeleteLocalRef(jHandle);
- if (jAudioPort == NULL) {
- return (jint)AUDIO_JAVA_ERROR;
+ jAudioPort->reset(env->NewObject(gAudioPortClass, gAudioPortCstor,
+ jHandle.get(), // handle
+ 0, // role
+ NULL, // name
+ NULL, // samplingRates
+ NULL, // channelMasks
+ NULL, // channelIndexMasks
+ NULL, // formats
+ NULL)); // gains
+
+ if (*jAudioPort == nullptr) {
+ return AUDIO_JAVA_ERROR;
}
ALOGV("convertAudioPortConfigFromNative jAudioPort created for handle %d",
nAudioPortConfig->id);
@@ -1089,6 +1088,9 @@
audioportCreated = true;
}
+ ScopedLocalRef<jobject> jAudioGainConfig(env, nullptr);
+ ScopedLocalRef<jobject> jAudioGain(env, nullptr);
+
bool useInMask = audio_port_config_has_input_direction(nAudioPortConfig);
audio_channel_mask_t nMask;
@@ -1102,36 +1104,26 @@
gainIndex, nAudioPortConfig->gain.mode);
if (audioportCreated) {
ALOGV("convertAudioPortConfigFromNative creating gain");
- jAudioGain = env->NewObject(gAudioGainClass, gAudioGainCstor,
- gainIndex,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0);
+ jAudioGain.reset(env->NewObject(gAudioGainClass, gAudioGainCstor, gainIndex, 0, 0, 0, 0,
+ 0, 0, 0, 0));
if (jAudioGain == NULL) {
ALOGV("convertAudioPortConfigFromNative creating gain FAILED");
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
} else {
ALOGV("convertAudioPortConfigFromNative reading gain from port");
- jobjectArray jGains = (jobjectArray)env->GetObjectField(jAudioPort,
- gAudioPortFields.mGains);
+ ScopedLocalRef<jobjectArray>
+ jGains(env,
+ static_cast<jobjectArray>(env->GetObjectField(jAudioPort->get(),
+ gAudioPortFields.mGains)));
if (jGains == NULL) {
ALOGV("convertAudioPortConfigFromNative could not get gains from port");
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
- jAudioGain = env->GetObjectArrayElement(jGains, gainIndex);
- env->DeleteLocalRef(jGains);
+ jAudioGain.reset(env->GetObjectArrayElement(jGains.get(), gainIndex));
if (jAudioGain == NULL) {
ALOGV("convertAudioPortConfigFromNative could not get gain at index %d", gainIndex);
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
}
int numValues;
@@ -1143,8 +1135,7 @@
jGainValues = env->NewIntArray(numValues);
if (jGainValues == NULL) {
ALOGV("convertAudioPortConfigFromNative could not create gain values %d", numValues);
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
env->SetIntArrayRegion(jGainValues, 0, numValues,
nAudioPortConfig->gain.values);
@@ -1158,19 +1149,14 @@
ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
}
- jAudioGainConfig = env->NewObject(gAudioGainConfigClass,
- gAudioGainConfigCstor,
- gainIndex,
- jAudioGain,
- nAudioPortConfig->gain.mode,
- jMask,
- jGainValues,
- nAudioPortConfig->gain.ramp_duration_ms);
+ jAudioGainConfig.reset(env->NewObject(gAudioGainConfigClass, gAudioGainConfigCstor,
+ gainIndex, jAudioGain.get(),
+ nAudioPortConfig->gain.mode, jMask, jGainValues,
+ nAudioPortConfig->gain.ramp_duration_ms));
env->DeleteLocalRef(jGainValues);
if (jAudioGainConfig == NULL) {
ALOGV("convertAudioPortConfigFromNative could not create gain config");
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
}
jclass clazz;
@@ -1180,17 +1166,16 @@
methodID = gAudioPortConfigCstor;
ALOGV("convertAudioPortConfigFromNative building a generic port config");
} else {
- if (env->IsInstanceOf(jAudioPort, gAudioDevicePortClass)) {
+ if (env->IsInstanceOf(jAudioPort->get(), gAudioDevicePortClass)) {
clazz = gAudioDevicePortConfigClass;
methodID = gAudioDevicePortConfigCstor;
ALOGV("convertAudioPortConfigFromNative building a device config");
- } else if (env->IsInstanceOf(jAudioPort, gAudioMixPortClass)) {
+ } else if (env->IsInstanceOf(jAudioPort->get(), gAudioMixPortClass)) {
clazz = gAudioMixPortConfigClass;
methodID = gAudioMixPortConfigCstor;
ALOGV("convertAudioPortConfigFromNative building a mix config");
} else {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
}
nMask = (nAudioPortConfig->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK)
@@ -1204,8 +1189,8 @@
ALOGV("convertAudioPortConfigFromNative OUT mask java %x native %x", jMask, nMask);
}
- *jAudioPortConfig =
- env->NewObject(clazz, methodID, jAudioPort,
+ jAudioPortConfig->reset(
+ env->NewObject(clazz, methodID, jAudioPort->get(),
(nAudioPortConfig->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE)
? nAudioPortConfig->sample_rate
: AUDIO_CONFIG_BASE_INITIALIZER.sample_rate,
@@ -1214,31 +1199,14 @@
(nAudioPortConfig->config_mask & AUDIO_PORT_CONFIG_FORMAT)
? nAudioPortConfig->format
: AUDIO_CONFIG_BASE_INITIALIZER.format),
- jAudioGainConfig);
+ jAudioGainConfig.get()));
if (*jAudioPortConfig == NULL) {
ALOGV("convertAudioPortConfigFromNative could not create new port config");
- jStatus = (jint)AUDIO_JAVA_ERROR;
+ return AUDIO_JAVA_ERROR;
} else {
ALOGV("convertAudioPortConfigFromNative OK");
}
-
-exit:
- if (audioportCreated) {
- env->DeleteLocalRef(jAudioPort);
- if (jAudioGain != NULL) {
- env->DeleteLocalRef(jAudioGain);
- }
- }
- if (jAudioGainConfig != NULL) {
- env->DeleteLocalRef(jAudioGainConfig);
- }
- return jStatus;
-}
-
-// TODO: pull out to separate file
-template <typename T, size_t N>
-static constexpr size_t array_size(const T (&)[N]) {
- return N;
+ return AUDIO_JAVA_SUCCESS;
}
static jintArray convertEncapsulationInfoFromNative(JNIEnv *env, uint32_t encapsulationInfo) {
@@ -1252,7 +1220,8 @@
}
}
jintArray result = env->NewIntArray(encapsulation.size());
- env->SetIntArrayRegion(result, 0, encapsulation.size(), (jint *)encapsulation.data());
+ env->SetIntArrayRegion(result, 0, encapsulation.size(),
+ reinterpret_cast<jint *>(encapsulation.data()));
return result;
}
@@ -1260,8 +1229,8 @@
std::stringstream &ss) {
ss << " num_audio_profiles " << nAudioPort->num_audio_profiles << " num_gains "
<< nAudioPort->num_gains;
- if (nAudioPort->num_audio_profiles > array_size(nAudioPort->audio_profiles) ||
- nAudioPort->num_gains > array_size(nAudioPort->gains)) {
+ if (nAudioPort->num_audio_profiles > std::size(nAudioPort->audio_profiles) ||
+ nAudioPort->num_gains > std::size(nAudioPort->gains)) {
return true;
}
for (size_t i = 0; i < nAudioPort->num_audio_profiles; ++i) {
@@ -1269,9 +1238,9 @@
<< " num_sample_rates " << nAudioPort->audio_profiles[i].num_sample_rates
<< " num_channel_masks " << nAudioPort->audio_profiles[i].num_channel_masks;
if (nAudioPort->audio_profiles[i].num_sample_rates >
- array_size(nAudioPort->audio_profiles[i].sample_rates) ||
+ std::size(nAudioPort->audio_profiles[i].sample_rates) ||
nAudioPort->audio_profiles[i].num_channel_masks >
- array_size(nAudioPort->audio_profiles[i].channel_masks)) {
+ std::size(nAudioPort->audio_profiles[i].channel_masks)) {
return true;
}
}
@@ -1309,7 +1278,8 @@
if (nAudioProfile->num_sample_rates) {
env->SetIntArrayRegion(jSamplingRates.get(), 0 /*start*/, nAudioProfile->num_sample_rates,
- (jint *)nAudioProfile->sample_rates);
+ const_cast<jint *>(reinterpret_cast<const jint *>(
+ nAudioProfile->sample_rates)));
}
// put the masks in the output arrays
@@ -1342,18 +1312,8 @@
return AUDIO_JAVA_SUCCESS;
}
-static jint convertAudioPortFromNative(JNIEnv *env, jobject *jAudioPort,
+static jint convertAudioPortFromNative(JNIEnv *env, ScopedLocalRef<jobject> *jAudioPort,
const struct audio_port_v7 *nAudioPort) {
- jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
- jintArray jEncapsulationModes = NULL;
- jintArray jEncapsulationMetadataTypes = NULL;
- jobjectArray jGains = NULL;
- jobject jHandle = NULL;
- jobject jAudioPortConfig = NULL;
- jstring jDeviceName = NULL;
- jobject jAudioProfiles = NULL;
- jobject jAudioDescriptors = nullptr;
- ScopedLocalRef<jobject> jPcmFloatProfileFromExtendedInteger(env, nullptr);
bool hasFloat = false;
bool useInMask;
@@ -1377,19 +1337,21 @@
} else {
ALOGE("%s", s.c_str());
}
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
useInMask = audio_has_input_direction(nAudioPort->type, nAudioPort->role);
- jAudioProfiles = env->NewObject(gArrayListClass, gArrayListMethods.cstor);
+ ScopedLocalRef<jobject> jAudioProfiles(env,
+ env->NewObject(gArrayListClass,
+ gArrayListMethods.cstor));
if (jAudioProfiles == nullptr) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
+ ScopedLocalRef<jobject> jPcmFloatProfileFromExtendedInteger(env, nullptr);
for (size_t i = 0; i < nAudioPort->num_audio_profiles; ++i) {
jobject jAudioProfile = nullptr;
+ jint jStatus = AUDIO_JAVA_SUCCESS;
jStatus = convertAudioProfileFromNative(env, &jAudioProfile, &nAudioPort->audio_profiles[i],
useInMask);
if (jStatus == AUDIO_JAVA_BAD_VALUE) {
@@ -1397,10 +1359,9 @@
continue;
}
if (jStatus != NO_ERROR) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
- env->CallBooleanMethod(jAudioProfiles, gArrayListMethods.add, jAudioProfile);
+ env->CallBooleanMethod(jAudioProfiles.get(), gArrayListMethods.add, jAudioProfile);
if (nAudioPort->audio_profiles[i].format == AUDIO_FORMAT_PCM_FLOAT) {
hasFloat = true;
@@ -1409,19 +1370,21 @@
audio_bytes_per_sample(nAudioPort->audio_profiles[i].format) > 2) {
ScopedLocalRef<jintArray>
jSamplingRates(env,
- (jintArray)
+ static_cast<jintArray>(
env->GetObjectField(jAudioProfile,
- gAudioProfileFields.mSamplingRates));
+ gAudioProfileFields
+ .mSamplingRates)));
ScopedLocalRef<jintArray>
jChannelMasks(env,
- (jintArray)
+ static_cast<jintArray>(
env->GetObjectField(jAudioProfile,
- gAudioProfileFields.mChannelMasks));
+ gAudioProfileFields.mChannelMasks)));
ScopedLocalRef<jintArray>
jChannelIndexMasks(env,
- (jintArray)env->GetObjectField(jAudioProfile,
- gAudioProfileFields
- .mChannelIndexMasks));
+ static_cast<jintArray>(
+ env->GetObjectField(jAudioProfile,
+ gAudioProfileFields
+ .mChannelIndexMasks)));
int encapsulationType =
env->GetIntField(jAudioProfile, gAudioProfileFields.mEncapsulationType);
@@ -1441,14 +1404,15 @@
// (replacing the zero pad). This ensures pre-S apps that look
// for ENCODING_PCM_FLOAT continue to see that encoding if the device supports
// extended precision integers.
- env->CallBooleanMethod(jAudioProfiles, gArrayListMethods.add,
+ env->CallBooleanMethod(jAudioProfiles.get(), gArrayListMethods.add,
jPcmFloatProfileFromExtendedInteger.get());
}
- jAudioDescriptors = env->NewObject(gArrayListClass, gArrayListMethods.cstor);
+ ScopedLocalRef<jobject> jAudioDescriptors(env,
+ env->NewObject(gArrayListClass,
+ gArrayListMethods.cstor));
if (jAudioDescriptors == nullptr) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
for (size_t i = 0; i < nAudioPort->num_extra_audio_descriptors; ++i) {
const auto &extraAudioDescriptor = nAudioPort->extra_audio_descriptors[i];
@@ -1478,15 +1442,16 @@
env->NewObject(gAudioDescriptorClass, gAudioDescriptorCstor,
standard, encapsulationType,
jDescriptor.get()));
- env->CallBooleanMethod(jAudioDescriptors, gArrayListMethods.add, jAudioDescriptor.get());
+ env->CallBooleanMethod(jAudioDescriptors.get(), gArrayListMethods.add,
+ jAudioDescriptor.get());
}
// gains
- jGains = env->NewObjectArray(nAudioPort->num_gains,
- gAudioGainClass, NULL);
- if (jGains == NULL) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ ScopedLocalRef<jobjectArray> jGains(env,
+ env->NewObjectArray(nAudioPort->num_gains, gAudioGainClass,
+ NULL));
+ if (jGains == nullptr) {
+ return AUDIO_JAVA_ERROR;
}
for (size_t j = 0; j < nAudioPort->num_gains; j++) {
@@ -1511,88 +1476,71 @@
nAudioPort->gains[j].min_ramp_ms,
nAudioPort->gains[j].max_ramp_ms);
if (jGain == NULL) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
- env->SetObjectArrayElement(jGains, j, jGain);
+ env->SetObjectArrayElement(jGains.get(), j, jGain);
env->DeleteLocalRef(jGain);
}
- jHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
- nAudioPort->id);
- if (jHandle == NULL) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ ScopedLocalRef<jobject> jHandle(env,
+ env->NewObject(gAudioHandleClass, gAudioHandleCstor,
+ nAudioPort->id));
+ if (jHandle == nullptr) {
+ return AUDIO_JAVA_ERROR;
}
- jDeviceName = env->NewStringUTF(nAudioPort->name);
-
+ ScopedLocalRef<jstring> jDeviceName(env, env->NewStringUTF(nAudioPort->name));
if (nAudioPort->type == AUDIO_PORT_TYPE_DEVICE) {
- ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
- jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
- jEncapsulationModes =
- convertEncapsulationInfoFromNative(env, nAudioPort->ext.device.encapsulation_modes);
- jEncapsulationMetadataTypes =
+ ScopedLocalRef<jintArray> jEncapsulationModes(
+ env,
+ convertEncapsulationInfoFromNative(env,
+ nAudioPort->ext.device.encapsulation_modes));
+ ScopedLocalRef<jintArray> jEncapsulationMetadataTypes(
+ env,
convertEncapsulationInfoFromNative(env,
nAudioPort->ext.device
- .encapsulation_metadata_types);
- *jAudioPort =
- env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor, jHandle, jDeviceName,
- jAudioProfiles, jGains, nAudioPort->ext.device.type, jAddress,
- jEncapsulationModes, jEncapsulationMetadataTypes, jAudioDescriptors);
+ .encapsulation_metadata_types));
+ ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type);
+ jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address);
+ jAudioPort->reset(
+ env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor, jHandle.get(),
+ jDeviceName.get(), jAudioProfiles.get(), jGains.get(),
+ nAudioPort->ext.device.type, jAddress, jEncapsulationModes.get(),
+ jEncapsulationMetadataTypes.get(), jAudioDescriptors.get()));
env->DeleteLocalRef(jAddress);
} else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
ALOGV("convertAudioPortFromNative is a mix");
- *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor, jHandle,
- nAudioPort->ext.mix.handle, nAudioPort->role, jDeviceName,
- jAudioProfiles, jGains);
+ jAudioPort->reset(env->NewObject(gAudioMixPortClass, gAudioMixPortCstor, jHandle.get(),
+ nAudioPort->ext.mix.handle, nAudioPort->role,
+ jDeviceName.get(), jAudioProfiles.get(), jGains.get()));
} else {
ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type);
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
if (*jAudioPort == NULL) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ return AUDIO_JAVA_ERROR;
}
- jStatus = convertAudioPortConfigFromNative(env,
- *jAudioPort,
- &jAudioPortConfig,
+ ScopedLocalRef<jobject> jAudioPortConfig(env, nullptr);
+
+ if (int jStatus = convertAudioPortConfigFromNative(env, jAudioPort, &jAudioPortConfig,
&nAudioPort->active_config);
- if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
}
- env->SetObjectField(*jAudioPort, gAudioPortFields.mActiveConfig, jAudioPortConfig);
+ env->SetObjectField(jAudioPort->get(), gAudioPortFields.mActiveConfig, jAudioPortConfig.get());
+ return AUDIO_JAVA_SUCCESS;
+}
-exit:
- if (jDeviceName != NULL) {
- env->DeleteLocalRef(jDeviceName);
+static bool setGeneration(JNIEnv *env, jintArray jGeneration, unsigned int generation1) {
+ ScopedIntArrayRW nGeneration(env, jGeneration);
+ if (nGeneration.get() == nullptr) {
+ return false;
+ } else {
+ nGeneration[0] = generation1;
+ return true;
}
- if (jEncapsulationModes != NULL) {
- env->DeleteLocalRef(jEncapsulationModes);
- }
- if (jEncapsulationMetadataTypes != NULL) {
- env->DeleteLocalRef(jEncapsulationMetadataTypes);
- }
- if (jAudioProfiles != NULL) {
- env->DeleteLocalRef(jAudioProfiles);
- }
- if (jGains != NULL) {
- env->DeleteLocalRef(jGains);
- }
- if (jHandle != NULL) {
- env->DeleteLocalRef(jHandle);
- }
- if (jAudioPortConfig != NULL) {
- env->DeleteLocalRef(jAudioPortConfig);
- }
- if (jAudioDescriptors != nullptr) {
- env->DeleteLocalRef(jAudioDescriptors);
- }
-
- return jStatus;
}
static jint
@@ -1603,23 +1551,22 @@
if (jPorts == NULL) {
ALOGE("listAudioPorts NULL AudioPort ArrayList");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (!env->IsInstanceOf(jPorts, gArrayListClass)) {
ALOGE("listAudioPorts not an arraylist");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
status_t status;
unsigned int generation1;
unsigned int generation;
unsigned int numPorts;
- jint *nGeneration;
- struct audio_port_v7 *nPorts = nullptr;
+ std::vector<audio_port_v7> nPorts;
int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
jint jStatus;
@@ -1638,43 +1585,39 @@
break;
}
if (numPorts == 0) {
- jStatus = (jint)AUDIO_JAVA_SUCCESS;
- goto exit;
+ return setGeneration(env, jGeneration, generation1) ? AUDIO_JAVA_SUCCESS
+ : AUDIO_JAVA_ERROR;
}
- nPorts = (struct audio_port_v7 *)realloc(nPorts, numPorts * sizeof(struct audio_port_v7));
+ nPorts.resize(numPorts);
status = AudioSystem::listAudioPorts(AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_NONE, &numPorts,
- nPorts, &generation);
+ &nPorts[0], &generation);
ALOGV("listAudioPorts AudioSystem::listAudioPorts numPorts %d generation %d generation1 %d",
numPorts, generation, generation1);
} while (generation1 != generation && status == NO_ERROR);
jStatus = nativeToJavaStatus(status);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ if (!setGeneration(env, jGeneration, generation1)) {
+ jStatus = AUDIO_JAVA_ERROR;
+ }
+ return jStatus;
}
for (size_t i = 0; i < numPorts; i++) {
- jobject jAudioPort = NULL;
+ ScopedLocalRef<jobject> jAudioPort(env, nullptr);
jStatus = convertAudioPortFromNative(env, &jAudioPort, &nPorts[i]);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ if (!setGeneration(env, jGeneration, generation1)) {
+ jStatus = AUDIO_JAVA_ERROR;
+ }
+ return jStatus;
}
- env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort);
- if (jAudioPort != NULL) {
- env->DeleteLocalRef(jAudioPort);
- }
+ env->CallBooleanMethod(jPorts, gArrayListMethods.add, jAudioPort.get());
}
-
-exit:
- nGeneration = env->GetIntArrayElements(jGeneration, NULL);
- if (nGeneration == NULL) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- } else {
- nGeneration[0] = generation1;
- env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
+ if (!setGeneration(env, jGeneration, generation1)) {
+ jStatus = AUDIO_JAVA_ERROR;
}
- free(nPorts);
return jStatus;
}
@@ -1687,64 +1630,56 @@
ALOGV("createAudioPatch");
if (jPatches == NULL || jSources == NULL || jSinks == NULL) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (env->GetArrayLength(jPatches) != 1) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
jint numSources = env->GetArrayLength(jSources);
if (numSources == 0 || numSources > AUDIO_PATCH_PORTS_MAX) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
jint numSinks = env->GetArrayLength(jSinks);
if (numSinks == 0 || numSinks > AUDIO_PATCH_PORTS_MAX) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
- audio_patch_handle_t handle = (audio_patch_handle_t)0;
- jobject jPatch = env->GetObjectArrayElement(jPatches, 0);
- jobject jPatchHandle = NULL;
+ audio_patch_handle_t handle = static_cast<audio_patch_handle_t>(AUDIO_PATCH_HANDLE_NONE);
+ ScopedLocalRef<jobject> jPatch(env, env->GetObjectArrayElement(jPatches, 0));
+ ScopedLocalRef<jobject> jPatchHandle(env, nullptr);
if (jPatch != NULL) {
- if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ if (!env->IsInstanceOf(jPatch.get(), gAudioPatchClass)) {
+ return AUDIO_JAVA_BAD_VALUE;
}
- jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
- handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
+ jPatchHandle.reset(env->GetObjectField(jPatch.get(), gAudioPatchFields.mHandle));
+ handle = static_cast<audio_patch_handle_t>(
+ env->GetIntField(jPatchHandle.get(), gAudioHandleFields.mId));
}
struct audio_patch nPatch = { .id = handle };
- jobject jSource = NULL;
- jobject jSink = NULL;
-
for (jint i = 0; i < numSources; i++) {
- jSource = env->GetObjectArrayElement(jSources, i);
- if (!env->IsInstanceOf(jSource, gAudioPortConfigClass)) {
- jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
- goto exit;
+ ScopedLocalRef<jobject> jSource(env, env->GetObjectArrayElement(jSources, i));
+ if (!env->IsInstanceOf(jSource.get(), gAudioPortConfigClass)) {
+ return AUDIO_JAVA_BAD_VALUE;
}
- jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource, false);
- env->DeleteLocalRef(jSource);
- jSource = NULL;
+ jStatus = convertAudioPortConfigToNative(env, &nPatch.sources[i], jSource.get(), false);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ return jStatus;
}
nPatch.num_sources++;
}
for (jint i = 0; i < numSinks; i++) {
- jSink = env->GetObjectArrayElement(jSinks, i);
- if (!env->IsInstanceOf(jSink, gAudioPortConfigClass)) {
- jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
- goto exit;
+ ScopedLocalRef<jobject> jSink(env, env->GetObjectArrayElement(jSinks, i));
+ if (!env->IsInstanceOf(jSink.get(), gAudioPortConfigClass)) {
+ return AUDIO_JAVA_BAD_VALUE;
}
- jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink, false);
- env->DeleteLocalRef(jSink);
- jSink = NULL;
+ jStatus = convertAudioPortConfigToNative(env, &nPatch.sinks[i], jSink.get(), false);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ return jStatus;
}
nPatch.num_sinks++;
}
@@ -1755,38 +1690,22 @@
jStatus = nativeToJavaStatus(status);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ return jStatus;
}
- if (jPatchHandle == NULL) {
- jPatchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
- handle);
- if (jPatchHandle == NULL) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ if (jPatchHandle == nullptr) {
+ jPatchHandle.reset(env->NewObject(gAudioHandleClass, gAudioHandleCstor, handle));
+ if (jPatchHandle == nullptr) {
+ return AUDIO_JAVA_ERROR;
}
- jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle, jSources, jSinks);
- if (jPatch == NULL) {
- jStatus = (jint)AUDIO_JAVA_ERROR;
- goto exit;
+ jPatch.reset(env->NewObject(gAudioPatchClass, gAudioPatchCstor, jPatchHandle.get(),
+ jSources, jSinks));
+ if (jPatch == nullptr) {
+ return AUDIO_JAVA_ERROR;
}
- env->SetObjectArrayElement(jPatches, 0, jPatch);
+ env->SetObjectArrayElement(jPatches, 0, jPatch.get());
} else {
- env->SetIntField(jPatchHandle, gAudioHandleFields.mId, handle);
- }
-
-exit:
- if (jPatchHandle != NULL) {
- env->DeleteLocalRef(jPatchHandle);
- }
- if (jPatch != NULL) {
- env->DeleteLocalRef(jPatch);
- }
- if (jSource != NULL) {
- env->DeleteLocalRef(jSource);
- }
- if (jSink != NULL) {
- env->DeleteLocalRef(jSink);
+ env->SetIntField(jPatchHandle.get(), gAudioHandleFields.mId, handle);
}
return jStatus;
}
@@ -1797,16 +1716,17 @@
{
ALOGV("releaseAudioPatch");
if (jPatch == NULL) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
- audio_patch_handle_t handle = (audio_patch_handle_t)0;
+ audio_patch_handle_t handle = static_cast<audio_patch_handle_t>(AUDIO_PATCH_HANDLE_NONE);
jobject jPatchHandle = NULL;
if (!env->IsInstanceOf(jPatch, gAudioPatchClass)) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
jPatchHandle = env->GetObjectField(jPatch, gAudioPatchFields.mHandle);
- handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
+ handle = static_cast<audio_patch_handle_t>(
+ env->GetIntField(jPatchHandle, gAudioHandleFields.mId));
env->DeleteLocalRef(jPatchHandle);
ALOGV("AudioSystem::releaseAudioPatch");
@@ -1823,28 +1743,22 @@
ALOGV("listAudioPatches");
if (jPatches == NULL) {
ALOGE("listAudioPatches NULL AudioPatch ArrayList");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (!env->IsInstanceOf(jPatches, gArrayListClass)) {
ALOGE("listAudioPatches not an arraylist");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (jGeneration == NULL || env->GetArrayLength(jGeneration) != 1) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
status_t status;
unsigned int generation1;
unsigned int generation;
unsigned int numPatches;
- jint *nGeneration;
- struct audio_patch *nPatches = NULL;
- jobjectArray jSources = NULL;
- jobject jSource = NULL;
- jobjectArray jSinks = NULL;
- jobject jSink = NULL;
- jobject jPatch = NULL;
+ std::vector<audio_patch> nPatches;
int attempts = MAX_PORT_GENERATION_SYNC_ATTEMPTS;
jint jStatus;
@@ -1865,15 +1779,13 @@
break;
}
if (numPatches == 0) {
- jStatus = (jint)AUDIO_JAVA_SUCCESS;
- goto exit;
+ return setGeneration(env, jGeneration, generation1) ? AUDIO_JAVA_SUCCESS
+ : AUDIO_JAVA_ERROR;
}
- nPatches = (struct audio_patch *)realloc(nPatches, numPatches * sizeof(struct audio_patch));
+ nPatches.resize(numPatches);
- status = AudioSystem::listAudioPatches(&numPatches,
- nPatches,
- &generation);
+ status = AudioSystem::listAudioPatches(&numPatches, &nPatches[0], &generation);
ALOGV("listAudioPatches AudioSystem::listAudioPatches numPatches %d generation %d generation1 %d",
numPatches, generation, generation1);
@@ -1881,15 +1793,21 @@
jStatus = nativeToJavaStatus(status);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ if (!setGeneration(env, jGeneration, generation1)) {
+ jStatus = AUDIO_JAVA_ERROR;
+ }
+ return jStatus;
}
for (size_t i = 0; i < numPatches; i++) {
+ ScopedLocalRef<jobject> jPatch(env, nullptr);
+ ScopedLocalRef<jobjectArray> jSources(env, nullptr);
+ ScopedLocalRef<jobjectArray> jSinks(env, nullptr);
jobject patchHandle = env->NewObject(gAudioHandleClass, gAudioHandleCstor,
nPatches[i].id);
if (patchHandle == NULL) {
- jStatus = AUDIO_JAVA_ERROR;
- goto exit;
+ setGeneration(env, jGeneration, generation1);
+ return AUDIO_JAVA_ERROR;
}
ALOGV("listAudioPatches patch %zu num_sources %d num_sinks %d",
i, nPatches[i].num_sources, nPatches[i].num_sinks);
@@ -1897,96 +1815,67 @@
env->SetIntField(patchHandle, gAudioHandleFields.mId, nPatches[i].id);
// load sources
- jSources = env->NewObjectArray(nPatches[i].num_sources,
- gAudioPortConfigClass, NULL);
- if (jSources == NULL) {
- jStatus = AUDIO_JAVA_ERROR;
- goto exit;
+ jSources.reset(env->NewObjectArray(nPatches[i].num_sources, gAudioPortConfigClass, NULL));
+ if (jSources == nullptr) {
+ setGeneration(env, jGeneration, generation1);
+ return AUDIO_JAVA_ERROR;
}
for (size_t j = 0; j < nPatches[i].num_sources; j++) {
- jStatus = convertAudioPortConfigFromNative(env,
- NULL,
- &jSource,
- &nPatches[i].sources[j]);
+ ScopedLocalRef<jobject> jSource(env, nullptr);
+ ScopedLocalRef<jobject> jAudioPort(env, nullptr);
+ jStatus = convertAudioPortConfigFromNative(env, &jAudioPort, &jSource,
+ &nPatches[i].sources[j]);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ if (!setGeneration(env, jGeneration, generation1)) {
+ jStatus = AUDIO_JAVA_ERROR;
+ }
+ return jStatus;
}
- env->SetObjectArrayElement(jSources, j, jSource);
- env->DeleteLocalRef(jSource);
- jSource = NULL;
+ env->SetObjectArrayElement(jSources.get(), j, jSource.get());
ALOGV("listAudioPatches patch %zu source %zu is a %s handle %d",
i, j,
nPatches[i].sources[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
nPatches[i].sources[j].id);
}
// load sinks
- jSinks = env->NewObjectArray(nPatches[i].num_sinks,
- gAudioPortConfigClass, NULL);
- if (jSinks == NULL) {
- jStatus = AUDIO_JAVA_ERROR;
- goto exit;
+ jSinks.reset(env->NewObjectArray(nPatches[i].num_sinks, gAudioPortConfigClass, NULL));
+ if (jSinks == nullptr) {
+ setGeneration(env, jGeneration, generation1);
+ return AUDIO_JAVA_ERROR;
}
for (size_t j = 0; j < nPatches[i].num_sinks; j++) {
- jStatus = convertAudioPortConfigFromNative(env,
- NULL,
- &jSink,
- &nPatches[i].sinks[j]);
+ ScopedLocalRef<jobject> jSink(env, nullptr);
+ ScopedLocalRef<jobject> jAudioPort(env, nullptr);
+ jStatus = convertAudioPortConfigFromNative(env, &jAudioPort, &jSink,
+ &nPatches[i].sinks[j]);
if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ if (!setGeneration(env, jGeneration, generation1)) {
+ jStatus = AUDIO_JAVA_ERROR;
+ }
+ return jStatus;
}
- env->SetObjectArrayElement(jSinks, j, jSink);
- env->DeleteLocalRef(jSink);
- jSink = NULL;
+ env->SetObjectArrayElement(jSinks.get(), j, jSink.get());
ALOGV("listAudioPatches patch %zu sink %zu is a %s handle %d",
i, j,
nPatches[i].sinks[j].type == AUDIO_PORT_TYPE_DEVICE ? "device" : "mix",
nPatches[i].sinks[j].id);
}
- jPatch = env->NewObject(gAudioPatchClass, gAudioPatchCstor,
- patchHandle, jSources, jSinks);
- env->DeleteLocalRef(jSources);
- jSources = NULL;
- env->DeleteLocalRef(jSinks);
- jSinks = NULL;
- if (jPatch == NULL) {
+ jPatch.reset(env->NewObject(gAudioPatchClass, gAudioPatchCstor, patchHandle, jSources.get(),
+ jSinks.get()));
+ if (jPatch == nullptr) {
jStatus = AUDIO_JAVA_ERROR;
- goto exit;
+ setGeneration(env, jGeneration, generation1);
+ return AUDIO_JAVA_ERROR;
}
- env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch);
- env->DeleteLocalRef(jPatch);
- jPatch = NULL;
+ env->CallBooleanMethod(jPatches, gArrayListMethods.add, jPatch.get());
}
-
-exit:
-
- nGeneration = env->GetIntArrayElements(jGeneration, NULL);
- if (nGeneration == NULL) {
+ if (!setGeneration(env, jGeneration, generation1)) {
jStatus = AUDIO_JAVA_ERROR;
- } else {
- nGeneration[0] = generation1;
- env->ReleaseIntArrayElements(jGeneration, nGeneration, 0);
}
-
- if (jSources != NULL) {
- env->DeleteLocalRef(jSources);
- }
- if (jSource != NULL) {
- env->DeleteLocalRef(jSource);
- }
- if (jSinks != NULL) {
- env->DeleteLocalRef(jSinks);
- }
- if (jSink != NULL) {
- env->DeleteLocalRef(jSink);
- }
- if (jPatch != NULL) {
- env->DeleteLocalRef(jPatch);
- }
- free(nPatches);
return jStatus;
}
@@ -2035,7 +1924,7 @@
}
auto paa = JNIAudioAttributeHelper::makeUnique();
jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
audio_port_handle_t handle;
@@ -2052,8 +1941,7 @@
android_media_AudioSystem_stopAudioSource(JNIEnv *env, jobject clazz, jint handle)
{
ALOGV("stopAudioSource");
- status_t status = AudioSystem::stopAudioSource(
- static_cast <audio_port_handle_t>(handle));
+ status_t status = AudioSystem::stopAudioSource(static_cast<audio_port_handle_t>(handle));
ALOGV("AudioSystem::stopAudioSource() returned %d", status);
return nativeToJavaStatus(status);
}
@@ -2085,7 +1973,7 @@
static jint
android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
{
- return (jint) AudioSystem::getAudioHwSyncForSession((audio_session_t) sessionId);
+ return AudioSystem::getAudioHwSyncForSession(static_cast<audio_session_t>(sessionId));
}
static void
@@ -2204,11 +2092,11 @@
{
nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
- nAudioMix->mDeviceType = (audio_devices_t)
- env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType);
+ nAudioMix->mDeviceType =
+ static_cast<audio_devices_t>(env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType));
- jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioMix,
- gAudioMixFields.mDeviceAddress);
+ jstring jDeviceAddress =
+ static_cast<jstring>(env->GetObjectField(jAudioMix, gAudioMixFields.mDeviceAddress));
const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
nAudioMix->mDeviceAddress = String8(nDeviceAddress);
env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
@@ -2227,8 +2115,8 @@
nAudioMix->mVoiceCommunicationCaptureAllowed =
env->GetBooleanField(jRule, gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed);
env->DeleteLocalRef(jRule);
- jobjectArray jCriteria = (jobjectArray)env->CallObjectMethod(jRuleCriteria,
- gArrayListMethods.toArray);
+ jobjectArray jCriteria = static_cast<jobjectArray>(
+ env->CallObjectMethod(jRuleCriteria, gArrayListMethods.toArray));
env->DeleteLocalRef(jRuleCriteria);
jint numCriteria = env->GetArrayLength(jCriteria);
@@ -2264,8 +2152,8 @@
auto paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAttributes, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
- return jStatus;
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
}
if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
nCriterion.mValue.mUsage = paa->usage;
@@ -2283,7 +2171,7 @@
env->DeleteLocalRef(jCriteria);
- return (jint)AUDIO_JAVA_SUCCESS;
+ return AUDIO_JAVA_SUCCESS;
}
static jint
@@ -2293,34 +2181,29 @@
ALOGV("registerPolicyMixes");
if (jMixesList == NULL) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (!env->IsInstanceOf(jMixesList, gArrayListClass)) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
- jobjectArray jMixes = (jobjectArray)env->CallObjectMethod(jMixesList,
- gArrayListMethods.toArray);
+ jobjectArray jMixes =
+ static_cast<jobjectArray>(env->CallObjectMethod(jMixesList, gArrayListMethods.toArray));
jint numMixes = env->GetArrayLength(jMixes);
if (numMixes > MAX_MIXES_PER_POLICY) {
numMixes = MAX_MIXES_PER_POLICY;
}
status_t status;
- jint jStatus;
- jobject jAudioMix = NULL;
Vector <AudioMix> mixes;
for (jint i = 0; i < numMixes; i++) {
- jAudioMix = env->GetObjectArrayElement(jMixes, i);
- if (!env->IsInstanceOf(jAudioMix, gAudioMixClass)) {
- jStatus = (jint)AUDIO_JAVA_BAD_VALUE;
- goto exit;
+ ScopedLocalRef<jobject> jAudioMix(env, env->GetObjectArrayElement(jMixes, i));
+ if (!env->IsInstanceOf(jAudioMix.get(), gAudioMixClass)) {
+ return AUDIO_JAVA_BAD_VALUE;
}
AudioMix mix;
- jStatus = convertAudioMixToNative(env, &mix, jAudioMix);
- env->DeleteLocalRef(jAudioMix);
- jAudioMix = NULL;
- if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
+ if (jint jStatus = convertAudioMixToNative(env, &mix, jAudioMix.get());
+ jStatus != AUDIO_JAVA_SUCCESS) {
+ return jStatus;
}
mixes.add(mix);
}
@@ -2329,16 +2212,7 @@
status = AudioSystem::registerPolicyMixes(mixes, registration);
ALOGV("AudioSystem::registerPolicyMixes() returned %d", status);
- jStatus = nativeToJavaStatus(status);
- if (jStatus != AUDIO_JAVA_SUCCESS) {
- goto exit;
- }
-
-exit:
- if (jAudioMix != NULL) {
- env->DeleteLocalRef(jAudioMix);
- }
- return jStatus;
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobject clazz,
@@ -2348,14 +2222,14 @@
if (results != NO_ERROR) {
return results;
}
- status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector);
- return (jint) nativeToJavaStatus(status);
+ status_t status = AudioSystem::setUidDeviceAffinities(uid, deviceVector);
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioSystem_removeUidDeviceAffinities(JNIEnv *env, jobject clazz,
jint uid) {
- status_t status = AudioSystem::removeUidDeviceAffinities((uid_t) uid);
- return (jint) nativeToJavaStatus(status);
+ status_t status = AudioSystem::removeUidDeviceAffinities(static_cast<uid_t>(uid));
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioSystem_setUserIdDeviceAffinities(JNIEnv *env, jobject clazz,
@@ -2366,14 +2240,14 @@
if (results != NO_ERROR) {
return results;
}
- status_t status = AudioSystem::setUserIdDeviceAffinities((int)userId, deviceVector);
- return (jint)nativeToJavaStatus(status);
+ status_t status = AudioSystem::setUserIdDeviceAffinities(userId, deviceVector);
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioSystem_removeUserIdDeviceAffinities(JNIEnv *env, jobject clazz,
jint userId) {
- status_t status = AudioSystem::removeUserIdDeviceAffinities((int)userId);
- return (jint)nativeToJavaStatus(status);
+ status_t status = AudioSystem::removeUserIdDeviceAffinities(userId);
+ return nativeToJavaStatus(status);
}
static jint
@@ -2386,19 +2260,18 @@
android_media_AudioSystem_getStreamVolumeDB(JNIEnv *env, jobject thiz,
jint stream, jint index, jint device)
{
- return (jfloat)AudioSystem::getStreamVolumeDB((audio_stream_type_t)stream,
- (int)index,
- (audio_devices_t)device);
+ return AudioSystem::getStreamVolumeDB(static_cast<audio_stream_type_t>(stream), index,
+ static_cast<audio_devices_t>(device));
}
static jint android_media_AudioSystem_getOffloadSupport(JNIEnv *env, jobject thiz, jint encoding,
jint sampleRate, jint channelMask,
jint channelIndexMask, jint streamType) {
audio_offload_info_t format = AUDIO_INFO_INITIALIZER;
- format.format = (audio_format_t) audioFormatToNative(encoding);
- format.sample_rate = (uint32_t) sampleRate;
+ format.format = static_cast<audio_format_t>(audioFormatToNative(encoding));
+ format.sample_rate = sampleRate;
format.channel_mask = nativeChannelMaskFromJavaChannelMasks(channelMask, channelIndexMask);
- format.stream_type = (audio_stream_type_t) streamType;
+ format.stream_type = static_cast<audio_stream_type_t>(streamType);
format.has_video = false;
format.is_streaming = false;
// offload duration unknown at this point:
@@ -2415,11 +2288,11 @@
if (jMicrophonesInfo == NULL) {
ALOGE("jMicrophonesInfo NULL MicrophoneInfo ArrayList");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (!env->IsInstanceOf(jMicrophonesInfo, gArrayListClass)) {
ALOGE("getMicrophones not an arraylist");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
jint jStatus;
@@ -2431,7 +2304,7 @@
return jStatus;
}
if (microphones.size() == 0) {
- jStatus = (jint)AUDIO_JAVA_SUCCESS;
+ jStatus = AUDIO_JAVA_SUCCESS;
return jStatus;
}
for (size_t i = 0; i < microphones.size(); i++) {
@@ -2453,7 +2326,7 @@
jint jStatus = AUDIO_JAVA_SUCCESS;
if (!env->IsInstanceOf(jEncodingFormatList, gArrayListClass)) {
ALOGE("%s: jEncodingFormatList not an ArrayList", __FUNCTION__);
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
std::vector<audio_format_t> encodingFormats;
status_t status =
@@ -2572,12 +2445,12 @@
android_media_AudioSystem_setSurroundFormatEnabled(JNIEnv *env, jobject thiz,
jint audioFormat, jboolean enabled)
{
- status_t status = AudioSystem::setSurroundFormatEnabled(audioFormatToNative(audioFormat),
- (bool)enabled);
+ status_t status =
+ AudioSystem::setSurroundFormatEnabled(audioFormatToNative(audioFormat), enabled);
if (status != NO_ERROR) {
ALOGE_IF(status != NO_ERROR, "AudioSystem::setSurroundFormatEnabled error %d", status);
}
- return (jint)nativeToJavaStatus(status);
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioSystem_getMaxChannelCount(JNIEnv *env, jobject thiz) {
@@ -2618,7 +2491,7 @@
status_t status = AudioSystem::setAssistantServicesUids(nativeUidsVector);
- return (jint)nativeToJavaStatus(status);
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioSystem_setActiveAssistantServicesUids(JNIEnv *env, jobject thiz,
@@ -2627,7 +2500,7 @@
status_t status = AudioSystem::setActiveAssistantServicesUids(nativeActiveUidsVector);
- return (jint)nativeToJavaStatus(status);
+ return nativeToJavaStatus(status);
}
static jint
@@ -2635,12 +2508,12 @@
std::vector<uid_t> nativeUidsVector = convertJIntArrayToUidVector(env, uids);
status_t status = AudioSystem::setA11yServicesUids(nativeUidsVector);
- return (jint)nativeToJavaStatus(status);
+ return nativeToJavaStatus(status);
}
static jint android_media_AudioSystem_setCurrentImeUid(JNIEnv *env, jobject thiz, jint uid) {
status_t status = AudioSystem::setCurrentImeUid(uid);
- return (jint)nativeToJavaStatus(status);
+ return nativeToJavaStatus(status);
}
static jboolean
@@ -2658,7 +2531,7 @@
std::vector<audio_usage_t> nativeSystemUsagesVector;
if (systemUsages == nullptr) {
- return (jint) AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
int *nativeSystemUsages = nullptr;
@@ -2675,7 +2548,7 @@
}
status_t status = AudioSystem::setSupportedSystemUsages(nativeSystemUsagesVector);
- return (jint)nativeToJavaStatus(status);
+ return nativeToJavaStatus(status);
}
static jint
@@ -2686,16 +2559,16 @@
static jint
android_media_AudioSystem_setRttEnabled(JNIEnv *env, jobject thiz, jboolean enabled)
{
- return (jint) check_AudioSystem_Command(AudioSystem::setRttEnabled(enabled));
+ return check_AudioSystem_Command(AudioSystem::setRttEnabled(enabled));
}
static jint
android_media_AudioSystem_setAudioHalPids(JNIEnv *env, jobject clazz, jintArray jPids)
{
if (jPids == NULL) {
- return (jint) AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
- pid_t *nPidsArray = (pid_t *) env->GetIntArrayElements(jPids, NULL);
+ pid_t *nPidsArray = reinterpret_cast<pid_t *>(env->GetIntArrayElements(jPids, NULL));
std::vector<pid_t> nPids(nPidsArray, nPidsArray + env->GetArrayLength(jPids));
status_t status = AudioSystem::setAudioHalPids(nPids);
env->ReleaseIntArrayElements(jPids, nPidsArray, 0);
@@ -2719,9 +2592,9 @@
return results;
}
int status = check_AudioSystem_Command(
- AudioSystem::setDevicesRoleForStrategy((product_strategy_t)strategy,
- (device_role_t)role, nDevices));
- return (jint) status;
+ AudioSystem::setDevicesRoleForStrategy(static_cast<product_strategy_t>(strategy),
+ static_cast<device_role_t>(role), nDevices));
+ return status;
}
static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz,
@@ -2734,8 +2607,8 @@
return results;
}
int status = check_AudioSystem_Command(
- AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)strategy,
- (device_role_t)role, nDevices));
+ AudioSystem::removeDevicesRoleForStrategy(static_cast<product_strategy_t>(strategy),
+ static_cast<device_role_t>(role), nDevices));
return (jint)status;
}
@@ -2753,10 +2626,10 @@
jobject jDevices) {
AudioDeviceTypeAddrVector nDevices;
status_t status = check_AudioSystem_Command(
- AudioSystem::getDevicesForRoleAndStrategy((product_strategy_t)strategy,
- (device_role_t)role, nDevices));
+ AudioSystem::getDevicesForRoleAndStrategy(static_cast<product_strategy_t>(strategy),
+ static_cast<device_role_t>(role), nDevices));
if (status != NO_ERROR) {
- return (jint) status;
+ return status;
}
for (const auto &device : nDevices) {
jobject jAudioDeviceAttributes = NULL;
@@ -2779,9 +2652,10 @@
return results;
}
int status = check_AudioSystem_Command(
- AudioSystem::setDevicesRoleForCapturePreset((audio_source_t)capturePreset,
- (device_role_t)role, nDevices));
- return (jint)status;
+ AudioSystem::setDevicesRoleForCapturePreset(static_cast<audio_source_t>(capturePreset),
+ static_cast<device_role_t>(role),
+ nDevices));
+ return status;
}
static jint android_media_AudioSystem_addDevicesRoleForCapturePreset(
@@ -2793,9 +2667,10 @@
return results;
}
int status = check_AudioSystem_Command(
- AudioSystem::addDevicesRoleForCapturePreset((audio_source_t)capturePreset,
- (device_role_t)role, nDevices));
- return (jint)status;
+ AudioSystem::addDevicesRoleForCapturePreset(static_cast<audio_source_t>(capturePreset),
+ static_cast<device_role_t>(role),
+ nDevices));
+ return status;
}
static jint android_media_AudioSystem_removeDevicesRoleForCapturePreset(
@@ -2807,17 +2682,20 @@
return results;
}
int status = check_AudioSystem_Command(
- AudioSystem::removeDevicesRoleForCapturePreset((audio_source_t)capturePreset,
- (device_role_t)role, nDevices));
- return (jint)status;
+ AudioSystem::removeDevicesRoleForCapturePreset(static_cast<audio_source_t>(
+ capturePreset),
+ static_cast<device_role_t>(role),
+ nDevices));
+ return status;
}
static jint android_media_AudioSystem_clearDevicesRoleForCapturePreset(JNIEnv *env, jobject thiz,
jint capturePreset,
jint role) {
- return (jint)check_AudioSystem_Command(
- AudioSystem::clearDevicesRoleForCapturePreset((audio_source_t)capturePreset,
- (device_role_t)role));
+ return static_cast<jint>(check_AudioSystem_Command(
+ AudioSystem::clearDevicesRoleForCapturePreset(static_cast<audio_source_t>(
+ capturePreset),
+ static_cast<device_role_t>(role))));
}
static jint android_media_AudioSystem_getDevicesForRoleAndCapturePreset(JNIEnv *env, jobject thiz,
@@ -2826,10 +2704,12 @@
jobject jDevices) {
AudioDeviceTypeAddrVector nDevices;
status_t status = check_AudioSystem_Command(
- AudioSystem::getDevicesForRoleAndCapturePreset((audio_source_t)capturePreset,
- (device_role_t)role, nDevices));
+ AudioSystem::getDevicesForRoleAndCapturePreset(static_cast<audio_source_t>(
+ capturePreset),
+ static_cast<device_role_t>(role),
+ nDevices));
if (status != NO_ERROR) {
- return (jint)status;
+ return status;
}
for (const auto &device : nDevices) {
jobject jAudioDeviceAttributes = NULL;
@@ -2854,12 +2734,12 @@
// components call this method often
if (jDeviceArray == nullptr || maxResultSize == 0) {
ALOGE("%s invalid array to store AudioDeviceAttributes", __FUNCTION__);
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
- if (jStatus != (jint) AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
@@ -2888,7 +2768,7 @@
static jint android_media_AudioSystem_setVibratorInfos(JNIEnv *env, jobject thiz,
jobject jVibrators) {
if (!env->IsInstanceOf(jVibrators, gListClass)) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
const jint size = env->CallIntMethod(jVibrators, gListMethods.size);
std::vector<media::AudioVibratorInfo> vibratorInfos;
@@ -2896,7 +2776,7 @@
ScopedLocalRef<jobject> jVibrator(env,
env->CallObjectMethod(jVibrators, gListMethods.get, i));
if (!env->IsInstanceOf(jVibrator.get(), gVibratorClass)) {
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
media::AudioVibratorInfo vibratorInfo;
vibratorInfo.id = env->CallIntMethod(jVibrator.get(), gVibratorMethods.getId);
@@ -2907,7 +2787,7 @@
env->CallFloatMethod(jVibrator.get(), gVibratorMethods.getMaxAmplitude);
vibratorInfos.push_back(vibratorInfo);
}
- return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos));
+ return check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos));
}
static jobject android_media_AudioSystem_getSpatializer(JNIEnv *env, jobject thiz,
@@ -2929,8 +2809,8 @@
jobjectArray jDeviceArray) {
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
- return false;
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
+ return false;
}
AudioDeviceTypeAddrVector nDevices;
@@ -2943,7 +2823,7 @@
return false;
}
jStatus = createAudioDeviceTypeAddrFromJava(env, &device, jDevice);
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return false;
}
nDevices.push_back(device);
@@ -3000,7 +2880,7 @@
jobject jFormat, jobject jaa) {
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return DIRECT_NOT_SUPPORTED;
}
@@ -3023,20 +2903,20 @@
if (jAudioAttributes == nullptr) {
ALOGE("jAudioAttributes is NULL");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (jAudioProfilesList == nullptr) {
ALOGE("jAudioProfilesList is NULL");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
if (!env->IsInstanceOf(jAudioProfilesList, gArrayListClass)) {
ALOGE("jAudioProfilesList not an ArrayList");
- return (jint)AUDIO_JAVA_BAD_VALUE;
+ return AUDIO_JAVA_BAD_VALUE;
}
JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
- if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
@@ -3212,8 +3092,7 @@
static int android_media_AudioSystem_setBluetoothVariableLatencyEnabled(JNIEnv *env, jobject thiz,
jboolean enabled) {
- return (jint)check_AudioSystem_Command(
- AudioSystem::setBluetoothVariableLatencyEnabled(enabled));
+ return check_AudioSystem_Command(AudioSystem::setBluetoothVariableLatencyEnabled(enabled));
}
static jboolean android_media_AudioSystem_isBluetoothVariableLatencyEnabled(JNIEnv *env,
@@ -3227,191 +3106,182 @@
// ----------------------------------------------------------------------------
+#define MAKE_AUDIO_SYSTEM_METHOD(x) \
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG(#x, android_media_AudioSystem_##x)
+
static const JNINativeMethod gMethods[] =
- {{"setParameters", "(Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_setParameters},
- {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;",
- (void *)android_media_AudioSystem_getParameters},
- {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
- {"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
- {"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
- {"isStreamActiveRemotely", "(II)Z",
- (void *)android_media_AudioSystem_isStreamActiveRemotely},
- {"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
- {"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
- {"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
- {"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
- {"setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
- (void *)android_media_AudioSystem_setDeviceConnectionState},
- {"getDeviceConnectionState", "(ILjava/lang/String;)I",
- (void *)android_media_AudioSystem_getDeviceConnectionState},
- {"handleDeviceConfigChange", "(ILjava/lang/String;Ljava/lang/String;I)I",
- (void *)android_media_AudioSystem_handleDeviceConfigChange},
- {"setPhoneState", "(II)I", (void *)android_media_AudioSystem_setPhoneState},
- {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
- {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
- {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
- {"setStreamVolumeIndex", "(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
- {"getStreamVolumeIndex", "(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
- {"setVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;II)I",
- (void *)android_media_AudioSystem_setVolumeIndexForAttributes},
- {"getVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;I)I",
- (void *)android_media_AudioSystem_getVolumeIndexForAttributes},
- {"getMinVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;)I",
- (void *)android_media_AudioSystem_getMinVolumeIndexForAttributes},
- {"getMaxVolumeIndexForAttributes", "(Landroid/media/AudioAttributes;)I",
- (void *)android_media_AudioSystem_getMaxVolumeIndexForAttributes},
- {"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
- {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume},
- {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute},
- {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute},
- {"setMasterMono", "(Z)I", (void *)android_media_AudioSystem_setMasterMono},
- {"getMasterMono", "()Z", (void *)android_media_AudioSystem_getMasterMono},
- {"setMasterBalance", "(F)I", (void *)android_media_AudioSystem_setMasterBalance},
- {"getMasterBalance", "()F", (void *)android_media_AudioSystem_getMasterBalance},
- {"getPrimaryOutputSamplingRate", "()I",
- (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
- {"getPrimaryOutputFrameCount", "()I",
- (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
- {"getOutputLatency", "(I)I", (void *)android_media_AudioSystem_getOutputLatency},
- {"setLowRamDevice", "(ZJ)I", (void *)android_media_AudioSystem_setLowRamDevice},
- {"checkAudioFlinger", "()I", (void *)android_media_AudioSystem_checkAudioFlinger},
- {"setAudioFlingerBinder", "(Landroid/os/IBinder;)V",
- (void *)android_media_AudioSystem_setAudioFlingerBinder},
- {"listAudioPorts", "(Ljava/util/ArrayList;[I)I",
- (void *)android_media_AudioSystem_listAudioPorts},
- {"createAudioPatch",
- "([Landroid/media/AudioPatch;[Landroid/media/AudioPortConfig;[Landroid/media/"
- "AudioPortConfig;)I",
- (void *)android_media_AudioSystem_createAudioPatch},
- {"releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
- (void *)android_media_AudioSystem_releaseAudioPatch},
- {"listAudioPatches", "(Ljava/util/ArrayList;[I)I",
- (void *)android_media_AudioSystem_listAudioPatches},
- {"setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
- (void *)android_media_AudioSystem_setAudioPortConfig},
- {"startAudioSource", "(Landroid/media/AudioPortConfig;Landroid/media/AudioAttributes;)I",
- (void *)android_media_AudioSystem_startAudioSource},
- {"stopAudioSource", "(I)I", (void *)android_media_AudioSystem_stopAudioSource},
- {"getAudioHwSyncForSession", "(I)I",
- (void *)android_media_AudioSystem_getAudioHwSyncForSession},
- {"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
- (void *)android_media_AudioSystem_registerPolicyMixes},
- {"setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_setUidDeviceAffinities},
- {"removeUidDeviceAffinities", "(I)I",
- (void *)android_media_AudioSystem_removeUidDeviceAffinities},
- {"native_register_dynamic_policy_callback", "()V",
- (void *)android_media_AudioSystem_registerDynPolicyCallback},
- {"native_register_recording_callback", "()V",
- (void *)android_media_AudioSystem_registerRecordingCallback},
- {"native_register_routing_callback", "()V",
- (void *)android_media_AudioSystem_registerRoutingCallback},
- {"native_register_vol_range_init_req_callback", "()V",
- (void *)android_media_AudioSystem_registerVolRangeInitReqCallback},
- {"systemReady", "()I", (void *)android_media_AudioSystem_systemReady},
- {"getStreamVolumeDB", "(III)F", (void *)android_media_AudioSystem_getStreamVolumeDB},
- {"native_get_offload_support", "(IIIII)I",
- (void *)android_media_AudioSystem_getOffloadSupport},
- {"getMicrophones", "(Ljava/util/ArrayList;)I",
- (void *)android_media_AudioSystem_getMicrophones},
- {"getSurroundFormats", "(Ljava/util/Map;)I",
- (void *)android_media_AudioSystem_getSurroundFormats},
- {"getReportedSurroundFormats", "(Ljava/util/ArrayList;)I",
- (void *)android_media_AudioSystem_getReportedSurroundFormats},
- {"setSurroundFormatEnabled", "(IZ)I",
- (void *)android_media_AudioSystem_setSurroundFormatEnabled},
- {"setAssistantServicesUids", "([I)I",
- (void *)android_media_AudioSystem_setAssistantServicesUids},
- {"setActiveAssistantServicesUids", "([I)I",
- (void *)android_media_AudioSystem_setActiveAssistantServicesUids},
- {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
- {"isHapticPlaybackSupported", "()Z",
- (void *)android_media_AudioSystem_isHapticPlaybackSupported},
- {"isUltrasoundSupported", "()Z", (void *)android_media_AudioSystem_isUltrasoundSupported},
- {"getHwOffloadFormatsSupportedForBluetoothMedia", "(ILjava/util/ArrayList;)I",
- (void *)android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia},
- {"setSupportedSystemUsages", "([I)I",
- (void *)android_media_AudioSystem_setSupportedSystemUsages},
- {"setAllowedCapturePolicy", "(II)I",
- (void *)android_media_AudioSystem_setAllowedCapturePolicy},
- {"setRttEnabled", "(Z)I", (void *)android_media_AudioSystem_setRttEnabled},
- {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids},
- {"isCallScreeningModeSupported", "()Z",
- (void *)android_media_AudioSystem_isCallScreeningModeSupported},
- {"setDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_setDevicesRoleForStrategy},
- {"removeDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_removeDevicesRoleForStrategy},
- {"clearDevicesRoleForStrategy", "(II)I",
- (void *)android_media_AudioSystem_clearDevicesRoleForStrategy},
- {"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
- (void *)android_media_AudioSystem_getDevicesForRoleAndStrategy},
- {"setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_setDevicesRoleForCapturePreset},
- {"addDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_addDevicesRoleForCapturePreset},
- {"removeDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_removeDevicesRoleForCapturePreset},
- {"clearDevicesRoleForCapturePreset", "(II)I",
- (void *)android_media_AudioSystem_clearDevicesRoleForCapturePreset},
- {"getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I",
- (void *)android_media_AudioSystem_getDevicesForRoleAndCapturePreset},
- {"getDevicesForAttributes",
- "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;Z)I",
- (void *)android_media_AudioSystem_getDevicesForAttributes},
- {"setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I",
- (void *)android_media_AudioSystem_setUserIdDeviceAffinities},
- {"removeUserIdDeviceAffinities", "(I)I",
- (void *)android_media_AudioSystem_removeUserIdDeviceAffinities},
- {"setCurrentImeUid", "(I)I", (void *)android_media_AudioSystem_setCurrentImeUid},
- {"setVibratorInfos", "(Ljava/util/List;)I",
- (void *)android_media_AudioSystem_setVibratorInfos},
- {"nativeGetSpatializer",
- "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;",
- (void *)android_media_AudioSystem_getSpatializer},
- {"canBeSpatialized",
- "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
- "[Landroid/media/AudioDeviceAttributes;)Z",
- (void *)android_media_AudioSystem_canBeSpatialized},
- {"nativeGetSoundDose", "(Landroid/media/ISoundDoseCallback;)Landroid/os/IBinder;",
- (void *)android_media_AudioSystem_nativeGetSoundDose},
- {"getDirectPlaybackSupport",
- "(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
- (void *)android_media_AudioSystem_getDirectPlaybackSupport},
- {"getDirectProfilesForAttributes",
- "(Landroid/media/AudioAttributes;Ljava/util/ArrayList;)I",
- (void *)android_media_AudioSystem_getDirectProfilesForAttributes},
- {"getSupportedMixerAttributes", "(ILjava/util/List;)I",
- (void *)android_media_AudioSystem_getSupportedMixerAttributes},
- {"setPreferredMixerAttributes",
- "(Landroid/media/AudioAttributes;IILandroid/media/AudioMixerAttributes;)I",
- (void *)android_media_AudioSystem_setPreferredMixerAttributes},
- {"getPreferredMixerAttributes", "(Landroid/media/AudioAttributes;ILjava/util/List;)I",
- (void *)android_media_AudioSystem_getPreferredMixerAttributes},
- {"clearPreferredMixerAttributes", "(Landroid/media/AudioAttributes;II)I",
- (void *)android_media_AudioSystem_clearPreferredMixerAttributes},
- {"supportsBluetoothVariableLatency", "()Z",
- (void *)android_media_AudioSystem_supportsBluetoothVariableLatency},
- {"setBluetoothVariableLatencyEnabled", "(Z)I",
- (void *)android_media_AudioSystem_setBluetoothVariableLatencyEnabled},
- {"isBluetoothVariableLatencyEnabled", "()Z",
- (void *)android_media_AudioSystem_isBluetoothVariableLatencyEnabled}};
+ {MAKE_AUDIO_SYSTEM_METHOD(setParameters),
+ MAKE_AUDIO_SYSTEM_METHOD(getParameters),
+ MAKE_AUDIO_SYSTEM_METHOD(muteMicrophone),
+ MAKE_AUDIO_SYSTEM_METHOD(isMicrophoneMuted),
+ MAKE_AUDIO_SYSTEM_METHOD(isStreamActive),
+ MAKE_AUDIO_SYSTEM_METHOD(isStreamActiveRemotely),
+ MAKE_AUDIO_SYSTEM_METHOD(isSourceActive),
+ MAKE_AUDIO_SYSTEM_METHOD(newAudioSessionId),
+ MAKE_AUDIO_SYSTEM_METHOD(newAudioPlayerId),
+ MAKE_AUDIO_SYSTEM_METHOD(newAudioRecorderId),
+ MAKE_JNI_NATIVE_METHOD("setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
+ android_media_AudioSystem_setDeviceConnectionState),
+ MAKE_AUDIO_SYSTEM_METHOD(getDeviceConnectionState),
+ MAKE_AUDIO_SYSTEM_METHOD(handleDeviceConfigChange),
+ MAKE_AUDIO_SYSTEM_METHOD(setPhoneState),
+ MAKE_AUDIO_SYSTEM_METHOD(setForceUse),
+ MAKE_AUDIO_SYSTEM_METHOD(getForceUse),
+ MAKE_AUDIO_SYSTEM_METHOD(initStreamVolume),
+ MAKE_AUDIO_SYSTEM_METHOD(setStreamVolumeIndex),
+ MAKE_AUDIO_SYSTEM_METHOD(getStreamVolumeIndex),
+ MAKE_JNI_NATIVE_METHOD("setVolumeIndexForAttributes",
+ "(Landroid/media/AudioAttributes;II)I",
+ android_media_AudioSystem_setVolumeIndexForAttributes),
+ MAKE_JNI_NATIVE_METHOD("getVolumeIndexForAttributes",
+ "(Landroid/media/AudioAttributes;I)I",
+ android_media_AudioSystem_getVolumeIndexForAttributes),
+ MAKE_JNI_NATIVE_METHOD("getMinVolumeIndexForAttributes",
+ "(Landroid/media/AudioAttributes;)I",
+ android_media_AudioSystem_getMinVolumeIndexForAttributes),
+ MAKE_JNI_NATIVE_METHOD("getMaxVolumeIndexForAttributes",
+ "(Landroid/media/AudioAttributes;)I",
+ android_media_AudioSystem_getMaxVolumeIndexForAttributes),
+ MAKE_AUDIO_SYSTEM_METHOD(setMasterVolume),
+ MAKE_AUDIO_SYSTEM_METHOD(getMasterVolume),
+ MAKE_AUDIO_SYSTEM_METHOD(setMasterMute),
+ MAKE_AUDIO_SYSTEM_METHOD(getMasterMute),
+ MAKE_AUDIO_SYSTEM_METHOD(setMasterMono),
+ MAKE_AUDIO_SYSTEM_METHOD(getMasterMono),
+ MAKE_AUDIO_SYSTEM_METHOD(setMasterBalance),
+ MAKE_AUDIO_SYSTEM_METHOD(getMasterBalance),
+ MAKE_AUDIO_SYSTEM_METHOD(getPrimaryOutputSamplingRate),
+ MAKE_AUDIO_SYSTEM_METHOD(getPrimaryOutputFrameCount),
+ MAKE_AUDIO_SYSTEM_METHOD(getOutputLatency),
+ MAKE_AUDIO_SYSTEM_METHOD(setLowRamDevice),
+ MAKE_AUDIO_SYSTEM_METHOD(checkAudioFlinger),
+ MAKE_JNI_NATIVE_METHOD("setAudioFlingerBinder", "(Landroid/os/IBinder;)V",
+ android_media_AudioSystem_setAudioFlingerBinder),
+ MAKE_JNI_NATIVE_METHOD("listAudioPorts", "(Ljava/util/ArrayList;[I)I",
+ android_media_AudioSystem_listAudioPorts),
+ MAKE_JNI_NATIVE_METHOD("createAudioPatch",
+ "([Landroid/media/AudioPatch;[Landroid/media/"
+ "AudioPortConfig;[Landroid/media/AudioPortConfig;)I",
+ android_media_AudioSystem_createAudioPatch),
+ MAKE_JNI_NATIVE_METHOD("releaseAudioPatch", "(Landroid/media/AudioPatch;)I",
+ android_media_AudioSystem_releaseAudioPatch),
+ MAKE_JNI_NATIVE_METHOD("listAudioPatches", "(Ljava/util/ArrayList;[I)I",
+ android_media_AudioSystem_listAudioPatches),
+ MAKE_JNI_NATIVE_METHOD("setAudioPortConfig", "(Landroid/media/AudioPortConfig;)I",
+ android_media_AudioSystem_setAudioPortConfig),
+ MAKE_JNI_NATIVE_METHOD("startAudioSource",
+ "(Landroid/media/AudioPortConfig;Landroid/media/AudioAttributes;)I",
+ android_media_AudioSystem_startAudioSource),
+ MAKE_AUDIO_SYSTEM_METHOD(stopAudioSource),
+ MAKE_AUDIO_SYSTEM_METHOD(getAudioHwSyncForSession),
+ MAKE_JNI_NATIVE_METHOD("registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
+ android_media_AudioSystem_registerPolicyMixes),
+ MAKE_JNI_NATIVE_METHOD("setUidDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+ android_media_AudioSystem_setUidDeviceAffinities),
+ MAKE_AUDIO_SYSTEM_METHOD(removeUidDeviceAffinities),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_dynamic_policy_callback",
+ android_media_AudioSystem_registerDynPolicyCallback),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_recording_callback",
+ android_media_AudioSystem_registerRecordingCallback),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_routing_callback",
+ android_media_AudioSystem_registerRoutingCallback),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_register_vol_range_init_req_callback",
+ android_media_AudioSystem_registerVolRangeInitReqCallback),
+ MAKE_AUDIO_SYSTEM_METHOD(systemReady),
+ MAKE_AUDIO_SYSTEM_METHOD(getStreamVolumeDB),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_get_offload_support",
+ android_media_AudioSystem_getOffloadSupport),
+ MAKE_JNI_NATIVE_METHOD("getMicrophones", "(Ljava/util/ArrayList;)I",
+ android_media_AudioSystem_getMicrophones),
+ MAKE_JNI_NATIVE_METHOD("getSurroundFormats", "(Ljava/util/Map;)I",
+ android_media_AudioSystem_getSurroundFormats),
+ MAKE_JNI_NATIVE_METHOD("getReportedSurroundFormats", "(Ljava/util/ArrayList;)I",
+ android_media_AudioSystem_getReportedSurroundFormats),
+ MAKE_AUDIO_SYSTEM_METHOD(setSurroundFormatEnabled),
+ MAKE_AUDIO_SYSTEM_METHOD(setAssistantServicesUids),
+ MAKE_AUDIO_SYSTEM_METHOD(setActiveAssistantServicesUids),
+ MAKE_AUDIO_SYSTEM_METHOD(setA11yServicesUids),
+ MAKE_AUDIO_SYSTEM_METHOD(isHapticPlaybackSupported),
+ MAKE_AUDIO_SYSTEM_METHOD(isUltrasoundSupported),
+ MAKE_JNI_NATIVE_METHOD(
+ "getHwOffloadFormatsSupportedForBluetoothMedia", "(ILjava/util/ArrayList;)I",
+ android_media_AudioSystem_getHwOffloadFormatsSupportedForBluetoothMedia),
+ MAKE_AUDIO_SYSTEM_METHOD(setSupportedSystemUsages),
+ MAKE_AUDIO_SYSTEM_METHOD(setAllowedCapturePolicy),
+ MAKE_AUDIO_SYSTEM_METHOD(setRttEnabled),
+ MAKE_AUDIO_SYSTEM_METHOD(setAudioHalPids),
+ MAKE_AUDIO_SYSTEM_METHOD(isCallScreeningModeSupported),
+ MAKE_JNI_NATIVE_METHOD("setDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
+ android_media_AudioSystem_setDevicesRoleForStrategy),
+ MAKE_JNI_NATIVE_METHOD("removeDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I",
+ android_media_AudioSystem_removeDevicesRoleForStrategy),
+ MAKE_AUDIO_SYSTEM_METHOD(clearDevicesRoleForStrategy),
+ MAKE_JNI_NATIVE_METHOD("getDevicesForRoleAndStrategy", "(IILjava/util/List;)I",
+ android_media_AudioSystem_getDevicesForRoleAndStrategy),
+ MAKE_JNI_NATIVE_METHOD("setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+ android_media_AudioSystem_setDevicesRoleForCapturePreset),
+ MAKE_JNI_NATIVE_METHOD("addDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+ android_media_AudioSystem_addDevicesRoleForCapturePreset),
+ MAKE_JNI_NATIVE_METHOD("removeDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I",
+ android_media_AudioSystem_removeDevicesRoleForCapturePreset),
+ MAKE_AUDIO_SYSTEM_METHOD(clearDevicesRoleForCapturePreset),
+ MAKE_JNI_NATIVE_METHOD("getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I",
+ android_media_AudioSystem_getDevicesForRoleAndCapturePreset),
+ MAKE_JNI_NATIVE_METHOD("getDevicesForAttributes",
+ "(Landroid/media/AudioAttributes;[Landroid/media/"
+ "AudioDeviceAttributes;Z)I",
+ android_media_AudioSystem_getDevicesForAttributes),
+ MAKE_JNI_NATIVE_METHOD("setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I",
+ android_media_AudioSystem_setUserIdDeviceAffinities),
+ MAKE_AUDIO_SYSTEM_METHOD(removeUserIdDeviceAffinities),
+ MAKE_AUDIO_SYSTEM_METHOD(setCurrentImeUid),
+ MAKE_JNI_NATIVE_METHOD("setVibratorInfos", "(Ljava/util/List;)I",
+ android_media_AudioSystem_setVibratorInfos),
+ MAKE_JNI_NATIVE_METHOD("nativeGetSpatializer",
+ "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;",
+ android_media_AudioSystem_getSpatializer),
+ MAKE_JNI_NATIVE_METHOD("canBeSpatialized",
+ "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
+ "[Landroid/media/AudioDeviceAttributes;)Z",
+ android_media_AudioSystem_canBeSpatialized),
+ MAKE_JNI_NATIVE_METHOD("nativeGetSoundDose",
+ "(Landroid/media/ISoundDoseCallback;)Landroid/os/IBinder;",
+ android_media_AudioSystem_nativeGetSoundDose),
+ MAKE_JNI_NATIVE_METHOD("getDirectPlaybackSupport",
+ "(Landroid/media/AudioFormat;Landroid/media/AudioAttributes;)I",
+ android_media_AudioSystem_getDirectPlaybackSupport),
+ MAKE_JNI_NATIVE_METHOD("getDirectProfilesForAttributes",
+ "(Landroid/media/AudioAttributes;Ljava/util/ArrayList;)I",
+ android_media_AudioSystem_getDirectProfilesForAttributes),
+ MAKE_JNI_NATIVE_METHOD("getSupportedMixerAttributes", "(ILjava/util/List;)I",
+ android_media_AudioSystem_getSupportedMixerAttributes),
+ MAKE_JNI_NATIVE_METHOD("setPreferredMixerAttributes",
+ "(Landroid/media/AudioAttributes;IILandroid/media/"
+ "AudioMixerAttributes;)I",
+ android_media_AudioSystem_setPreferredMixerAttributes),
+ MAKE_JNI_NATIVE_METHOD("getPreferredMixerAttributes",
+ "(Landroid/media/AudioAttributes;ILjava/util/List;)I",
+ android_media_AudioSystem_getPreferredMixerAttributes),
+ MAKE_JNI_NATIVE_METHOD("clearPreferredMixerAttributes",
+ "(Landroid/media/AudioAttributes;II)I",
+ android_media_AudioSystem_clearPreferredMixerAttributes),
+ MAKE_AUDIO_SYSTEM_METHOD(supportsBluetoothVariableLatency),
+ MAKE_AUDIO_SYSTEM_METHOD(setBluetoothVariableLatencyEnabled),
+ MAKE_AUDIO_SYSTEM_METHOD(isBluetoothVariableLatencyEnabled)};
-static const JNINativeMethod gEventHandlerMethods[] = {
- {"native_setup",
- "(Ljava/lang/Object;)V",
- (void *)android_media_AudioSystem_eventHandlerSetup},
- {"native_finalize",
- "()V",
- (void *)android_media_AudioSystem_eventHandlerFinalize},
-};
+static const JNINativeMethod gEventHandlerMethods[] =
+ {MAKE_JNI_NATIVE_METHOD("native_setup", "(Ljava/lang/Object;)V",
+ android_media_AudioSystem_eventHandlerSetup),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_finalize",
+ android_media_AudioSystem_eventHandlerFinalize)};
-static const JNINativeMethod gFrameworkCapabilities[] = {
- {"native_getMaxChannelCount", "()I", (void *)android_media_AudioSystem_getMaxChannelCount},
- {"native_getMaxSampleRate", "()I", (void *)android_media_AudioSystem_getMaxSampleRate},
- {"native_getMinSampleRate", "()I", (void *)android_media_AudioSystem_getMinSampleRate},
-};
+static const JNINativeMethod gFrameworkCapabilities[] =
+ {MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_getMaxChannelCount",
+ android_media_AudioSystem_getMaxChannelCount),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_getMaxSampleRate",
+ android_media_AudioSystem_getMaxSampleRate),
+ MAKE_JNI_NATIVE_METHOD_AUTOSIG("native_getMinSampleRate",
+ android_media_AudioSystem_getMinSampleRate)};
int register_android_media_AudioSystem(JNIEnv *env)
{
@@ -3589,7 +3459,7 @@
gClsAudioTrackRoutingProxy =
android::FindClassOrDie(env, "android/media/AudioTrackRoutingProxy");
// make sure this reference doesn't get deleted
- gClsAudioTrackRoutingProxy = (jclass)env->NewGlobalRef(gClsAudioTrackRoutingProxy);
+ gClsAudioTrackRoutingProxy = static_cast<jclass>(env->NewGlobalRef(gClsAudioTrackRoutingProxy));
gMidAudioTrackRoutingProxy_ctor =
android::GetMethodIDOrDie(env, gClsAudioTrackRoutingProxy, "<init>", "(J)V");
@@ -3600,7 +3470,8 @@
gClsAudioRecordRoutingProxy =
android::FindClassOrDie(env, "android/media/AudioRecordRoutingProxy");
// make sure this reference doesn't get deleted
- gClsAudioRecordRoutingProxy = (jclass)env->NewGlobalRef(gClsAudioRecordRoutingProxy);
+ gClsAudioRecordRoutingProxy =
+ static_cast<jclass>(env->NewGlobalRef(gClsAudioRecordRoutingProxy));
gMidAudioRecordRoutingProxy_ctor =
android::GetMethodIDOrDie(env, gClsAudioRecordRoutingProxy, "<init>", "(J)V");
diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp
index 2df74b0..eda5075 100644
--- a/core/jni/android_os_UEventObserver.cpp
+++ b/core/jni/android_os_UEventObserver.cpp
@@ -71,7 +71,11 @@
}
buffer[length] = '\0';
- ALOGV("Received uevent message: %s", buffer);
+ IF_ALOGV() {
+ std::string message(buffer, length);
+ std::replace(message.begin(), message.end(), '\0', ' ');
+ ALOGV("Received uevent message: %s", message.c_str());
+ }
if (isMatch(buffer, length)) {
// Assume the message is ASCII.
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 0bc0878..f97d41b 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -42,6 +42,13 @@
return NULL;
}
+ // b/274058082: Pass a copy of the key character map to avoid concurrent
+ // access
+ std::shared_ptr<KeyCharacterMap> map = deviceInfo.getKeyCharacterMap();
+ if (map != nullptr) {
+ map = std::make_shared<KeyCharacterMap>(*map);
+ }
+
ScopedLocalRef<jstring> descriptorObj(env,
env->NewStringUTF(deviceInfo.getIdentifier().descriptor.c_str()));
if (!descriptorObj.get()) {
@@ -61,8 +68,8 @@
: NULL));
ScopedLocalRef<jobject> kcmObj(env,
- android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
- deviceInfo.getKeyCharacterMap()));
+ android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
+ map));
if (!kcmObj.get()) {
return NULL;
}
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 9017d58..da308b2 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -292,21 +292,31 @@
}
public:
- static NativeLibrariesIterator* create(ZipFileRO* zipFile, bool debuggable) {
- void* cookie = nullptr;
+ static base::expected<std::unique_ptr<NativeLibrariesIterator>, int32_t> create(
+ ZipFileRO* zipFile, bool debuggable) {
// Do not specify a suffix to find both .so files and gdbserver.
- if (!zipFile->startIteration(&cookie, APK_LIB.data(), nullptr /* suffix */)) {
- return nullptr;
+ auto result = zipFile->startIterationOrError(APK_LIB.data(), nullptr /* suffix */);
+ if (!result.ok()) {
+ return base::unexpected(result.error());
}
- return new NativeLibrariesIterator(zipFile, debuggable, cookie);
+ return std::unique_ptr<NativeLibrariesIterator>(
+ new NativeLibrariesIterator(zipFile, debuggable, result.value()));
}
- ZipEntryRO next() {
- ZipEntryRO next = nullptr;
- while ((next = mZipFile->nextEntry(mCookie)) != nullptr) {
+ base::expected<ZipEntryRO, int32_t> next() {
+ ZipEntryRO nextEntry;
+ while (true) {
+ auto next = mZipFile->nextEntryOrError(mCookie);
+ if (!next.ok()) {
+ return base::unexpected(next.error());
+ }
+ nextEntry = next.value();
+ if (nextEntry == nullptr) {
+ break;
+ }
// Make sure this entry has a filename.
- if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
+ if (mZipFile->getEntryFileName(nextEntry, fileName, sizeof(fileName))) {
continue;
}
@@ -317,7 +327,7 @@
}
}
- return next;
+ return nextEntry;
}
inline const char* currentEntry() const {
@@ -348,19 +358,28 @@
return INSTALL_FAILED_INVALID_APK;
}
- std::unique_ptr<NativeLibrariesIterator> it(
- NativeLibrariesIterator::create(zipFile, debuggable));
- if (it.get() == nullptr) {
+ auto result = NativeLibrariesIterator::create(zipFile, debuggable);
+ if (!result.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
+ std::unique_ptr<NativeLibrariesIterator> it(std::move(result.value()));
const ScopedUtfChars cpuAbi(env, javaCpuAbi);
if (cpuAbi.c_str() == nullptr) {
// This would've thrown, so this return code isn't observable by Java.
return INSTALL_FAILED_INVALID_APK;
}
- ZipEntryRO entry = nullptr;
- while ((entry = it->next()) != nullptr) {
+
+ while (true) {
+ auto next = it->next();
+ if (!next.ok()) {
+ return INSTALL_FAILED_INVALID_APK;
+ }
+ auto entry = next.value();
+ if (entry == nullptr) {
+ break;
+ }
+
const char* fileName = it->currentEntry();
const char* lastSlash = it->lastSlash();
@@ -388,11 +407,11 @@
return INSTALL_FAILED_INVALID_APK;
}
- std::unique_ptr<NativeLibrariesIterator> it(
- NativeLibrariesIterator::create(zipFile, debuggable));
- if (it.get() == nullptr) {
+ auto result = NativeLibrariesIterator::create(zipFile, debuggable);
+ if (!result.ok()) {
return INSTALL_FAILED_INVALID_APK;
}
+ std::unique_ptr<NativeLibrariesIterator> it(std::move(result.value()));
const int numAbis = env->GetArrayLength(supportedAbisArray);
@@ -402,9 +421,17 @@
supportedAbis.emplace_back(env, (jstring)env->GetObjectArrayElement(supportedAbisArray, i));
}
- ZipEntryRO entry = nullptr;
int status = NO_NATIVE_LIBRARIES;
- while ((entry = it->next()) != nullptr) {
+ while (true) {
+ auto next = it->next();
+ if (!next.ok()) {
+ return INSTALL_FAILED_INVALID_APK;
+ }
+ auto entry = next.value();
+ if (entry == nullptr) {
+ break;
+ }
+
// We're currently in the lib/ directory of the APK, so it does have some native
// code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the
// libraries match.
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index ce806a0..c368fa8 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -356,6 +356,7 @@
GWP_ASAN_LEVEL_DEFAULT = 3 << 21,
NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23,
PROFILEABLE = 1 << 24,
+ DEBUG_ENABLE_PTRACE = 1 << 25,
};
enum UnsolicitedZygoteMessageTypes : uint32_t {
@@ -1887,8 +1888,10 @@
}
// Set process properties to enable debugging if required.
- if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) {
+ if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_PTRACE) != 0) {
EnableDebugger();
+ // Don't pass unknown flag to the ART runtime.
+ runtime_flags &= ~RuntimeFlags::DEBUG_ENABLE_PTRACE;
}
if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) {
// simpleperf needs the process to be dumpable to profile it.
diff --git a/core/res/res/drawable-watch/input_method_item_background.xml b/core/res/res/drawable-watch/input_method_item_background.xml
new file mode 100644
index 0000000..1097773
--- /dev/null
+++ b/core/res/res/drawable-watch/input_method_item_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="172dp"
+ android:height="52dp"
+ android:viewportWidth="172"
+ android:viewportHeight="52" >
+
+ <group>
+ <clip-path
+ android:pathData="M26 0H146C160.359 0 172 11.6406 172 26C172 40.3594 160.359 52 146 52H26C11.6406 52 0 40.3594 0 26C0 11.6406 11.6406 0 26 0Z"
+ />
+
+ <path
+ android:pathData="M0 0V52H172V0"
+ android:fillColor="#262523"
+ />
+ </group>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable-watch/input_method_item_background_selected.xml b/core/res/res/drawable-watch/input_method_item_background_selected.xml
new file mode 100644
index 0000000..17a4c2b5
--- /dev/null
+++ b/core/res/res/drawable-watch/input_method_item_background_selected.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="172dp"
+ android:height="52dp"
+ android:viewportWidth="172"
+ android:viewportHeight="52" >
+
+ <group>
+ <clip-path
+ android:pathData="M26 0H146C160.359 0 172 11.6406 172 26C172 40.3594 160.359 52 146 52H26C11.6406 52 0 40.3594 0 26C0 11.6406 11.6406 0 26 0Z"
+ />
+
+ <group
+ android:translateX="0.49"
+ android:translateY="-5.604"
+ android:pivotX="86"
+ android:pivotY="26"
+ android:scaleX="2.924"
+ android:scaleY="22.357"
+ android:rotation="45.256" >
+
+ <path
+ android:pathData="M0 0V52H172V0" >
+
+ <aapt:attr name="android:fillColor" >
+ <gradient
+ android:type="linear"
+ android:startX="43"
+ android:startY="26"
+ android:endX="129"
+ android:endY="26" >
+ <item
+ android:color="#00202124"
+ android:offset="0" />
+ <item
+ android:color="#80FCF7EB"
+ android:offset="1" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ </group>
+ </group>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/color/letterbox_background.xml b/core/res/res/drawable-watch/input_method_item_background_selector.xml
similarity index 72%
rename from core/res/res/color/letterbox_background.xml
rename to core/res/res/drawable-watch/input_method_item_background_selector.xml
index 955948a..1d8786f 100644
--- a/core/res/res/color/letterbox_background.xml
+++ b/core/res/res/drawable-watch/input_method_item_background_selector.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@color/system_neutral1_500" android:lStar="5" />
+ <item android:state_selected="false" android:drawable="@drawable/input_method_item_background"/>
+ <item android:state_selected="true" android:drawable="@drawable/input_method_item_background_selected"/>
</selector>
diff --git a/core/res/res/layout-watch/input_method_switch_dialog_title.xml b/core/res/res/layout-watch/input_method_switch_dialog_title.xml
new file mode 100644
index 0000000..3d53ade
--- /dev/null
+++ b/core/res/res/layout-watch/input_method_switch_dialog_title.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="172dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp"
+ android:layout_marginTop="20dp"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center" >
+
+ <TextView
+ android:id="@+id/alertTitle"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp"
+ android:gravity="center_vertical"
+ android:lineSpacingExtra="0sp"
+ android:text="@string/select_input_method"
+ android:textColor="#BDC1C6"
+ android:fontFamily="google-sans-text-medium"
+ android:letterSpacing="0.01"
+ android:textSize="15sp" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <!-- Hard keyboard switch -->
+
+ <LinearLayout
+ android:id="@+id/hard_keyboard_section"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:background="?attr/selectableItemBackground"
+ android:ellipsize="marquee"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ style="@style/InputMethodSwitchHardKeyboardText">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:text="@string/hardware"
+ android:textAppearance="?attr/textAppearanceListItem"
+ android:ellipsize="marquee" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="10"
+ android:text="@string/show_ime"
+ android:textAppearance="?attr/textAppearanceListItemSecondary"
+ android:textColor="?attr/textColorSecondary" />
+ </LinearLayout>
+
+ <Switch
+ android:id="@+id/hard_keyboard_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ style="@style/InputMethodSwitchHardKeyboardSwitch"/>
+ </LinearLayout>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/listDividerAlertDialog" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout-watch/input_method_switch_item.xml b/core/res/res/layout-watch/input_method_switch_item.xml
new file mode 100644
index 0000000..a77bd8f
--- /dev/null
+++ b/core/res/res/layout-watch/input_method_switch_item.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dialog_item"
+ android:layout_width="172dp"
+ android:layout_height="52dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginTop="68dp"
+ android:weightSum="100"
+ android:gravity="center"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="5.21"
+ android:background="@android:color/transparent"/>
+
+ <LinearLayout
+ android:id="@+id/title"
+ android:layout_width="0dp"
+ android:layout_height="52dp"
+ android:layout_weight="89.58"
+ android:duplicateParentState="true"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:paddingEnd="6dp"
+ android:paddingStart="6dp"
+ android:background="@drawable/input_method_item_background_selector" >
+
+ <LinearLayout
+ android:id="@+id/text_layout"
+ android:layout_width="124dp"
+ android:layout_height="match_parent"
+ android:duplicateParentState="true"
+ android:gravity="center_vertical"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center_vertical"
+ android:letterSpacing="0.01"
+ android:textColor="#FFFFFF"
+ android:maxLines="1"
+ android:fontFamily="google-sans-text-medium"
+ android:textSize="15sp" />
+
+ <TextView
+ android:id="@+id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp"
+ android:gravity="center_vertical"
+ android:letterSpacing="0.01"
+ android:textColor="#CAC5BC"
+ android:maxLines="1"
+ android:fontFamily="google-sans-text-medium"
+ android:textSize="13sp" />
+
+ </LinearLayout>
+
+ <RadioButton
+ android:id="@+id/radio"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:buttonTint="#E6FF7B"
+ android:clickable="false"
+ android:duplicateParentState="true"
+ android:focusable="false"
+ android:gravity="center"
+ android:scaleX="1"
+ android:scaleY="1" />
+
+
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="5.21"
+ android:background="@android:color/transparent"/>
+
+
+</LinearLayout>
+
diff --git a/core/res/res/layout-watch/input_method_switcher_list_layout.xml b/core/res/res/layout-watch/input_method_switcher_list_layout.xml
new file mode 100644
index 0000000..6311f8a
--- /dev/null
+++ b/core/res/res/layout-watch/input_method_switcher_list_layout.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<view class="com.android.internal.app.AlertController$RecycleListView"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@id/select_dialog_listview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:cacheColorHint="@null"
+ android:divider="?attr/listDividerAlertDialog"
+ android:scrollbars="vertical"
+ android:overScrollMode="ifContentScrolls"
+ android:textAlignment="viewStart"
+ android:clipToPadding="false"
+ android:paddingBottomNoButtons="@dimen/dialog_list_padding_bottom_no_buttons"
+ android:paddingTopNoTitle="@dimen/dialog_list_padding_top_no_title"
+ android:dividerHeight="@dimen/input_method_divider_height"/>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 910e1da..936f08a 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"WEIER"</string>
<string name="select_input_method" msgid="3971267998568587025">"Kies invoermetode"</string>
<string name="show_ime" msgid="6406112007347443383">"Hou dit op die skerm terwyl fisieke sleutelbord aktief is"</string>
- <string name="hardware" msgid="1800597768237606953">"Wys virtuele sleutelbord"</string>
+ <string name="hardware" msgid="3611039921284836033">"Gebruik skermsleutelbord"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Stel <xliff:g id="DEVICE_NAME">%s</xliff:g> op"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Stel fisieke sleutelborde op"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tik om taal en uitleg te kies"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Program is nie beskikbaar nie"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nie op die oomblik beskikbaar nie."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> is nie beskikbaar nie"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Toestemmingsversoek is onderdruk"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera is nie beskikbaar nie"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Gaan voort op foon"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofoon is nie beskikbaar nie"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou Android TV-toestel."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Jy kan nie nou toegang hiertoe op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie. Probeer eerder op jou foon."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Hierdie app versoek tans bykomende toestemmings, maar toestemmings kan nie in ’n stromingsessie verleen word nie. Verleen eers die toestemming op jou Android TV-toestel."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Hierdie app versoek tans bykomende toestemmings, maar toestemmings kan nie in ’n stromingsessie verleen word nie. Verleen eers die toestemming op jou tablet."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Hierdie app versoek tans bykomende toestemmings, maar toestemmings kan nie in ’n stromingsessie verleen word nie. Verleen eers die toestemming op jou foon."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Hierdie program versoek tans bykomende sekuriteit. Probeer eerder op jou Android TV-toestel."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Hierdie program versoek tans bykomende sekuriteit. Probeer eerder op jou tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Hierdie program versoek tans bykomende sekuriteit. Probeer eerder op jou foon."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kan nie toegang tot die foon se kamera op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kan nie toegang tot die tablet se kamera op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Jy kan nie toegang hiertoe kry terwyl daar gestroom word nie. Probeer eerder op jou foon."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan nie prent-in-prent sien terwyl jy stroom nie"</string>
<string name="system_locale_title" msgid="711882686834677268">"Stelselverstek"</string>
<string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Metgeselhorlosieprofiel se toestemming om horlosies te bestuur"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 40df279..8e2f1a3 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"አትቀበል"</string>
<string name="select_input_method" msgid="3971267998568587025">"የግቤት ስልት ምረጥ"</string>
<string name="show_ime" msgid="6406112007347443383">"አካላዊ የቁልፍ ሰሌዳ ገቢር ሆኖ ሳለ በማያ ገፅ ላይ አቆየው"</string>
- <string name="hardware" msgid="1800597768237606953">"ምናባዊ የቁልፍ ሰሌዳን አሳይ"</string>
+ <string name="hardware" msgid="3611039921284836033">"የማያ ገጽ ላይ የቁልፍ ሰሌዳ ይጠቀሙ"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g>ን ያዋቅሩ"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"አካላዊ የቁልፍ ሰሌዳዎችን ያዋቅሩ"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ቋንቋ እና አቀማመጥን ለመምረጥ መታ ያድርጉ"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"መተግበሪያ አይገኝም"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> አሁን አይገኝም።"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> አይገኝም"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"የፈቃድ ጥያቄ ታፍኗል"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ካሜራ አይገኝም"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"በስልክ ላይ ይቀጥሉ"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ማይክሮፎን አይገኝም"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በAndroid TV መሣሪያዎ ላይ ይሞክሩ።"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በጡባዊዎ ላይ ይሞክሩ።"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ይህ በዚህ ጊዜ በእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> ላይ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"ይህ መተግበሪያ ተጨማሪ ፈቃዶችን እየጠየቀ ነው፣ ነገር ግን ፈቃዶች በዥረት ክፍለ ጊዜ ውስጥ ሊሰጡ አይችሉም። መጀመሪያ በAndroid TV መሣሪያዎ ላይ ፍቃድ ይስጡ።"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"ይህ መተግበሪያ ተጨማሪ ፈቃዶችን እየጠየቀ ነው፣ ነገር ግን ፈቃዶች በዥረት ክፍለ ጊዜ ውስጥ ሊሰጡ አይችሉም። መጀመሪያ በጡባዊዎ ላይ ፍቃድ ይስጡ።"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"ይህ መተግበሪያ ተጨማሪ ፈቃዶችን እየጠየቀ ነው፣ ነገር ግን ፈቃዶች በዥረት ክፍለ ጊዜ ውስጥ ሊሰጡ አይችሉም። መጀመሪያ በስልክዎ ላይ ፍቃድ ይስጡ።"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"ይህ መተግበሪያ ተጨማሪ ደህንነትን እየጠየቀ ነው። በምትኩ በAndroid TV መሣሪያዎ ላይ ይሞክሩ።"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"ይህ መተግበሪያ ተጨማሪ ደህንነትን እየጠየቀ ነው። በምትኩ በጡባዊዎ ላይ ይሞክሩ።"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"ይህ መተግበሪያ ተጨማሪ ደህንነትን እየጠየቀ ነው። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"የስልኩን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ጡባዊውን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ዥረት በመልቀቅ ላይ ሳለ ይህ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"በዥረት በመልቀቅ ወቅት በሥዕል-ላይ-ሥዕል ማየት አይችሉም"</string>
<string name="system_locale_title" msgid="711882686834677268">"የሥርዓት ነባሪ"</string>
<string name="default_card_name" msgid="9198284935962911468">"ካርድ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"የእጅ ሰዓቶችን ለማስተዳደር የአጃቢ የእጅ ሰዓት መገለጫ ፍቃድ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 0df3ec4..e457782 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1400,7 +1400,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"رفض"</string>
<string name="select_input_method" msgid="3971267998568587025">"اختيار أسلوب الإدخال"</string>
<string name="show_ime" msgid="6406112007347443383">"استمرار عرضها على الشاشة عندما تكون لوحة المفاتيح الخارجية متصلة"</string>
- <string name="hardware" msgid="1800597768237606953">"إظهار لوحة المفاتيح الافتراضية"</string>
+ <string name="hardware" msgid="3611039921284836033">"استخدام لوحة المفاتيح على الشاشة"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"إعداد <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"إعداد لوحات المفاتيح الخارجية"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"انقر لاختيار لغة وتنسيق"</string>
@@ -1963,8 +1963,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"التطبيق غير متاح"</string>
<string name="app_blocked_message" msgid="542972921087873023">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> غير متاح الآن."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"تطبيق <xliff:g id="ACTIVITY">%1$s</xliff:g> غير متاح"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"تم إلغاء طلب الإذن"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"الكاميرا غير متاحة"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"الاستمرار على الهاتف"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"الميكروفون غير متاح"</string>
@@ -1975,12 +1974,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على جهاز Android TV بدلاً من ذلك."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على جهازك اللوحي بدلاً من ذلك."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"لا يمكن الوصول إلى هذا التطبيق على <xliff:g id="DEVICE">%1$s</xliff:g> في الوقت الحالي. حاوِل الوصول إليه على هاتفك بدلاً من ذلك."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"يطلب هذا التطبيق الحصول على أذونات إضافية، ولكن لا يمكن منح أذونات في جلسة بث. امنح الإذن على جهاز Android TV أولاً."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"يطلب هذا التطبيق الحصول على أذونات إضافية، ولكن لا يمكن منح أذونات في جلسة بث. امنح الإذن على جهازك اللوحي أولاً."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"يطلب هذا التطبيق الحصول على أذونات إضافية، ولكن لا يمكن منح أذونات في جلسة بث. امنح الإذن على هاتفك أولاً."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"يطلب هذا التطبيق الحصول على ميزات أمان إضافية. بدلاً من ذلك، جرِّب استخدام Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"يطلب هذا التطبيق الحصول على ميزات أمان إضافية. بدلاً من ذلك، جرِّب استخدام جهازك اللوحي."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"يطلب هذا التطبيق الحصول على ميزات أمان إضافية. بدلاً من ذلك، جرِّب استخدام هاتفك."</string>
@@ -2324,7 +2320,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"يتعذّر الوصول إلى كاميرا الهاتف من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"يتعذّر الوصول إلى كاميرا الجهاز اللوحي من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
<string name="vdm_secure_window" msgid="161700398158812314">"لا يمكن الوصول إلى هذا المحتوى أثناء البث. بدلاً من ذلك، جرِّب استخدام هاتفك."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"لا يمكن عرض نافذة ضمن النافذة أثناء البث."</string>
<string name="system_locale_title" msgid="711882686834677268">"الإعداد التلقائي للنظام"</string>
<string name="default_card_name" msgid="9198284935962911468">"رقم البطاقة <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"إذن الملف الشخصي في Companion Watch لإدارة الساعات"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index f172511..7c11dfc 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"প্ৰত্যাখ্যান কৰক"</string>
<string name="select_input_method" msgid="3971267998568587025">"ইনপুট পদ্ধতি বাছনি কৰক"</string>
<string name="show_ime" msgid="6406112007347443383">"কায়িক কীব’ৰ্ড সক্ৰিয় হৈ থাকোঁতে ইয়াক স্ক্ৰীনত ৰাখক"</string>
- <string name="hardware" msgid="1800597768237606953">"ভাৰ্শ্বুৱল কীব\'ৰ্ড দেখুৱাওক"</string>
+ <string name="hardware" msgid="3611039921284836033">"অন-স্ক্ৰীন কীব’ৰ্ড ব্যৱহাৰ কৰক"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> কনফিগাৰ কৰক"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ভৌতিক কীব’ৰ্ড কনফিগাৰ কৰক"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ভাষা আৰু চানেকি বাছনি কৰিবলৈ ইয়াত টিপক"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"এপ্টো উপলব্ধ নহয়"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূৰ্তত <xliff:g id="APP_NAME">%1$s</xliff:g> উপলব্ধ নহয়।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলব্ধ নহয়"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"অনুমতিৰ অনুৰোধ অৱদমন কৰা হৈছে"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"কেমেৰা উপলব্ধ নহয়"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ফ’নতে অব্যাহত ৰাখক"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"মাইক্ৰ’ফ’ন উপলব্ধ নহয়"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ Android TVত চেষ্টা কৰি চাওক।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ টেবলেটটোত চেষ্টা কৰি চাওক।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"এইটো এতিয়া আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ত এক্সেছ কৰিব পৰা নাযায়। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"এই এপ্টোৱে অতিৰিক্ত অনুমতিৰ বাবে অনুৰোধ কৰিছে, কিন্তু ষ্ট্ৰীমিং ছেশ্বনত অনুমতি দিব নোৱাৰি। আপোনাৰ Android TV ডিভাইচটোত প্ৰথমে অনুমতি দিয়ক।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"এই এপ্টোৱে অতিৰিক্ত অনুমতিৰ বাবে অনুৰোধ কৰিছে, কিন্তু ষ্ট্ৰীমিং ছেশ্বনত অনুমতি দিব নোৱাৰি। আপোনাৰ টেবলেটটোত প্ৰথমে অনুমতি দিয়ক।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"এই এপ্টোৱে অতিৰিক্ত অনুমতিৰ বাবে অনুৰোধ কৰিছে, কিন্তু ষ্ট্ৰীমিং ছেশ্বনত অনুমতি দিব নোৱাৰি। আপোনাৰ ফ’নটোত প্ৰথমে অনুমতি দিয়ক।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"এই এপ্টোৱে অতিৰিক্ত সুৰক্ষাৰ বাবে অনুৰোধ কৰিছে। তাৰ পৰিৱৰ্তে আপোনাৰ Android TV ডিভাইচত চেষ্টা কৰি চাওক।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"এই এপ্টোৱে অতিৰিক্ত সুৰক্ষাৰ বাবে অনুৰোধ কৰিছে। তাৰ পৰিৱৰ্তে আপোনাৰ টেবলেটত চেষ্টা কৰি চাওক।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"এই এপ্টোৱে অতিৰিক্ত সুৰক্ষাৰ বাবে অনুৰোধ কৰিছে। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা ফ’নটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা টেবলেটটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ষ্ট্ৰীম কৰি থকাৰ সময়ত এইটো এক্সেছ কৰিব নোৱাৰি। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ষ্ট্ৰীম কৰি থকাৰ সময়ত picture-in-picture চাব নোৱাৰি"</string>
<string name="system_locale_title" msgid="711882686834677268">"ছিষ্টেম ডিফ’ল্ট"</string>
<string name="default_card_name" msgid="9198284935962911468">"কাৰ্ড <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ঘড়ী পৰিচালনা কৰিবলৈ সহযোগী ঘড়ীৰ প্ৰ’ফাইলৰ অনুমতি"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index cf06e90..dbfdd3c 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RƏDD EDİN"</string>
<string name="select_input_method" msgid="3971267998568587025">"Daxiletmə metodunu seçin"</string>
<string name="show_ime" msgid="6406112007347443383">"Fiziki klaviatura aktiv olanda görünsün"</string>
- <string name="hardware" msgid="1800597768237606953">"Virtual klaviaturanı göstərin"</string>
+ <string name="hardware" msgid="3611039921284836033">"Ekran klaviaturası işlədin"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> cihazını konfiqurasiya edin"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Fiziki klaviaturaları konfiqurasiya edin"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Dil və tərtibatı seçmək üçün tıklayın"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Tətbiq əlçatan deyil"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hazırda əlçatan deyil."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> əlçatan deyil"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"İcazə sorğusu dayandırıldı"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera əlçatan deyil"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Telefonda davam edin"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon əlçatan deyil"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Android TV cihazınızda sınayın."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Planşetinizdə sınayın."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hazırda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızda buna giriş mümkün deyil. Telefonunuzda sınayın."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Bu tətbiqə əlavə icazələr lazımdır, lakin yayım sessiyasında icazə vermək olmur. Əvvəlcə Android TV cihazında icazə verin."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Bu tətbiqə əlavə icazələr lazımdır, lakin yayım sessiyasında icazə vermək olmur. Əvvəlcə planşetdə icazə verin."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Bu tətbiqə əlavə icazələr lazımdır, lakin yayım sessiyasında icazə vermək olmur. Əvvəlcə telefonda icazə verin."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Bu tətbiq əlavə təhlükəsizlik tələb edir. Android TV cihazınızda sınayın."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Bu tətbiq əlavə təhlükəsizlik tələb edir. Planşetinizdə sınayın."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Bu tətbiq əlavə təhlükəsizlik tələb edir. Telefonunuzda sınayın."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına giriş etmək olmur"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan planşetin kamerasına giriş etmək olmur"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Yayım zamanı buna giriş mümkün deyil. Telefonunuzda sınayın."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Yayım zamanı şəkildə şəkilə baxmaq mümkün deyil"</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistem defoltu"</string>
<string name="default_card_name" msgid="9198284935962911468">"KART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Saatları idarə etmək üçün Kompanyon Saat profili icazəsi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index d6eb21c..5c6187e 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ODBIJ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Izbor metoda unosa"</string>
<string name="show_ime" msgid="6406112007347443383">"Zadržava se na ekranu dok je fizička tastatura aktivna"</string>
- <string name="hardware" msgid="1800597768237606953">"Prikaži virtuelnu tastaturu"</string>
+ <string name="hardware" msgid="3611039921284836033">"Koristi tastaturu na ekranu"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurišite uređaj <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurišite fizičke tastature"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Dodirnite da biste izabrali jezik i raspored"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Zahtev za dozvolu je blokiran"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nije dostupna"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nastavite na telefonu"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon je nedostupan"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na Android TV uređaju."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ovoj aplikaciji trenutno ne može da se pristupi sa uređaja <xliff:g id="DEVICE">%1$s</xliff:g>. Probajte na telefonu."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Ova aplikacija zahteva dodatne dozvole, ali dozvole ne mogu da se daju u sesiji strimovanja. Prvo dajte dozvolu na Android TV uređaju."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Ova aplikacija zahteva dodatne dozvole, ali dozvole ne mogu da se daju u sesiji strimovanja. Prvo dajte dozvolu na tabletu."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Ova aplikacija zahteva dodatne dozvole, ali dozvole ne mogu da se daju u sesiji strimovanja. Prvo dajte dozvolu na telefonu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ova aplikacija zahteva dodatnu bezbednost. Probajte na Android TV uređaju."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ova aplikacija zahteva dodatnu bezbednost. Probajte na tabletu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ova aplikacija zahteva dodatnu bezbednost. Probajte na telefonu."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ne može da se pristupi kameri telefona sa <xliff:g id="DEVICE">%1$s</xliff:g> uređaja"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ne može da se pristupi kameri tableta sa <xliff:g id="DEVICE">%1$s</xliff:g> uređaja"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Ovom ne možete da pristupate tokom strimovanja. Probajte na telefonu."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ne možete da gledate sliku u slici pri strimovanju"</string>
<string name="system_locale_title" msgid="711882686834677268">"Podrazumevani sistemski"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Dozvola za profil pratećeg sata za upravljanje satovima"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 9e234e1..84e68dc 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1261,7 +1261,7 @@
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Запуск прыкладанняў."</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"Завяршэнне загрузкі."</string>
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Вы націснулі кнопку сілкавання. Звычайна ў выніку гэтага дзеяння выключаецца экран.\n\nПадчас наладжвання адбітка пальца злёгку дакраніцеся да кнопкі."</string>
- <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Каб завяршыць наладку, выключыце экран"</string>
+ <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Каб скончыць наладку, выключыце экран"</string>
<string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Выключыць"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"Працягнуць спраўджанне адбітка пальца?"</string>
<string name="fp_power_button_bp_message" msgid="2983163038168903393">"Вы націснулі кнопку сілкавання. Звычайна ў выніку гэтага дзеяння выключаецца экран.\n\nКаб спраўдзіць адбітак пальца, злёгку дакраніцеся да кнопкі."</string>
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"АДХІЛІЦЬ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Выберыце метад уводу"</string>
<string name="show_ime" msgid="6406112007347443383">"Захоўваць яе на экране ў той час, калі фізічная клавіятура актыўная"</string>
- <string name="hardware" msgid="1800597768237606953">"Паказаць віртуальную клавіятуру"</string>
+ <string name="hardware" msgid="3611039921284836033">"Экранная клавіятура"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Наладзьце прыладу \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\""</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Наладзьце фізічныя клавіятуры"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Дакраніцеся, каб выбраць мову і раскладку"</string>
@@ -1961,8 +1961,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Праграма недаступная"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" цяпер недаступная."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недаступна: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Запыт дазволу заблакіраваны"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера недаступная"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Працягніце на тэлефоне"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Мікрафон недаступны"</string>
@@ -1973,12 +1972,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць прыладу Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць планшэт."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Не ўдаецца атрымаць доступ з вашай прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Паспрабуйце скарыстаць тэлефон."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Гэта праграма запытвае дадатковыя дазволы, якія немагчыма даць падчас трансляцыі. Спачатку дайце дазвол на прыладзе Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Гэта праграма запытвае дадатковыя дазволы, якія немагчыма даць падчас трансляцыі. Спачатку дайце дазвол на планшэце."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Гэта праграма запытвае дадатковыя дазволы, якія немагчыма даць падчас трансляцыі. Спачатку дайце дазвол на тэлефоне."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Гэтай праграме патрабуецца дадатковая бяспека. Паспрабуйце скарыстаць прыладу Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Гэтай праграме патрабуецца дадатковая бяспека. Паспрабуйце скарыстаць планшэт."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Гэтай праграме патрабуецца дадатковая бяспека. Паспрабуйце скарыстаць тэлефон."</string>
@@ -2322,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не ўдалося атрымаць доступ да камеры тэлефона з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не ўдалося атрымаць доступ да камеры планшэта з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Не ўдаецца атрымаць доступ у час перадачы плынню. Паспрабуйце скарыстаць тэлефон."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Падчас перадачы плынню прагляд у рэжыме \"Відарыс у відарысе\" немагчымы"</string>
<string name="system_locale_title" msgid="711882686834677268">"Стандартная сістэмная налада"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дазвол для спадарожнай праграмы кіраваць гадзіннікамі"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ce02cd5..159f8df 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ОТХВЪРЛЯНЕ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Избор на метод на въвеждане"</string>
<string name="show_ime" msgid="6406112007347443383">"Показване на екрана, докато физическата клавиатура е активна"</string>
- <string name="hardware" msgid="1800597768237606953">"Показване на вирт. клавиатура"</string>
+ <string name="hardware" msgid="3611039921284836033">"Ползв. на екранната клавиатура"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Конфигуриране на <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Конфигуриране на физически клавиатури"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Докоснете, за да изберете език и подредба"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Приложението не е достъпно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"В момента няма достъп до <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> не е налице"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Заявката за разрешения е блокирана"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Няма достъп до камерата"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продължете на телефона"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофонът не е достъпен"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от устройството си с Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от таблета си."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Понастоящем не може да се осъществи достъп от устройството ви <xliff:g id="DEVICE">%1$s</xliff:g>. Вместо това опитайте от телефона си."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Това приложение изисква допълнителни разрешения, но те не могат да бъдат предоставени в сесия за поточно предаване. Първо ги предоставете на устройството си с Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Това приложение изисква допълнителни разрешения, но те не могат да бъдат предоставени в сесия за поточно предаване. Първо ги предоставете на таблета си."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Това приложение изисква допълнителни разрешения, но те не могат да бъдат предоставени в сесия за поточно предаване. Първо ги предоставете на телефона си."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Това приложение изисква допълнителна стъпка за сигурност. Вместо това опитайте от устройството си с Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Това приложение изисква допълнителна стъпка за сигурност. Вместо това опитайте от таблета си."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Това приложение изисква допълнителна стъпка за сигурност. Вместо това опитайте от телефона си."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Няма достъп до камерата на телефона от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Няма достъп до камерата на таблета от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"До това съдържание не може да се осъществи достъп при поточно предаване. Вместо това опитайте от телефона си."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Функцията „Картина в картината“ не е налице при поточно предаване"</string>
<string name="system_locale_title" msgid="711882686834677268">"Стандартно за системата"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Разрешение на придружаващото приложение за достъп до потребителския профил на часовника с цел управление на часовници"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2a1808c..f448078 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"অস্বীকার করুন"</string>
<string name="select_input_method" msgid="3971267998568587025">"ইনপুট পদ্ধতি বেছে নিন"</string>
<string name="show_ime" msgid="6406112007347443383">"ফিজিক্যাল কীবোর্ড সক্রিয় থাকার সময় এটিকে স্ক্রীনে রাখুন"</string>
- <string name="hardware" msgid="1800597768237606953">"ভার্চুয়াল কীবোর্ড দেখুন"</string>
+ <string name="hardware" msgid="3611039921284836033">"স্ক্রিনের কীবোর্ড ব্যবহার করুন"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> কনফিগার করুন"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ফিজিক্যাল কীবোর্ড কনফিগার করুন"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ভাষা ও লেআউট বেছে নিতে ট্যাপ করুন"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"অ্যাপ পাওয়া যাচ্ছে না"</string>
<string name="app_blocked_message" msgid="542972921087873023">"এই মুহূর্তে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ পাওয়া যাচ্ছে না।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> উপলভ্য নেই"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"অনুমতির অনুরোধ ব্লক করা হয়েছে"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ক্যামেরা উপলভ্য নেই"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ফোনে চালিয়ে যান"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"মাইক্রোফোন উপলভ্য নেই"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার Android TV ডিভাইস ব্যবহার করে দেখুন।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ট্যাবলেটে ব্যবহার করে দেখুন।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"এই সময়ে আপনার <xliff:g id="DEVICE">%1$s</xliff:g>-এ এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ফোনে ব্যবহার করে দেখুন।"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"এই অ্যাপ অতিরিক্ত অনুমতির জন্য অনুরোধ করছে, কিন্তু স্ট্রিমিং সেশন চলাকালীন অনুমতি দেওয়া যাবে না। প্রথমে আপনার Android TV ডিভাইসে অনুমতি দিন।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"এই অ্যাপ অতিরিক্ত অনুমতির জন্য অনুরোধ করছে, কিন্তু স্ট্রিমিং সেশন চলাকালীন অনুমতি দেওয়া যাবে না। প্রথমে আপনার ট্যাবলেটে অনুমতি দিন।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"এই অ্যাপ অতিরিক্ত অনুমতির জন্য অনুরোধ করছে, কিন্তু স্ট্রিমিং সেশন চলাকালীন অনুমতি দেওয়া যাবে না। প্রথমে আপনার ফোনে অনুমতি দিন।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"এই অ্যাপ অতিরিক্ত নিরাপত্তার জন্য অনুরোধ করছে। পরিবর্তে আপনার Android TV ডিভাইস ব্যবহার করে দেখুন।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"এই অ্যাপ অতিরিক্ত নিরাপত্তার জন্য অনুরোধ করছে। পরিবর্তে আপনার ট্যাবলেটে ব্যবহার করে দেখুন।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"এই অ্যাপ অতিরিক্ত নিরাপত্তার জন্য অনুরোধ করছে। পরিবর্তে আপনার ফোনে ব্যবহার করে দেখুন।"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপনার <xliff:g id="DEVICE">%1$s</xliff:g> থেকে ফোনের ক্যামেরা অ্যাক্সেস করা যাচ্ছে না"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপনার <xliff:g id="DEVICE">%1$s</xliff:g> থেকে ট্যাবলেটের ক্যামেরা অ্যাক্সেস করা যাচ্ছে না"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"স্ট্রিমিংয়ের সময় এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ফোনে ব্যবহার করে দেখুন।"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"স্ট্রিম করার সময় \'ছবির-মধ্যে-ছবি\' দেখা যাবে না"</string>
<string name="system_locale_title" msgid="711882686834677268">"সিস্টেম ডিফল্ট"</string>
<string name="default_card_name" msgid="9198284935962911468">"কার্ড <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ওয়াচ ম্যানেজ করতে, কম্প্যানিয়ন ওয়াচ প্রোফাইল সংক্রান্ত অনুমতি"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index e10fe6a..78daa1c 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ODBACI"</string>
<string name="select_input_method" msgid="3971267998568587025">"Odaberite način unosa"</string>
<string name="show_ime" msgid="6406112007347443383">"Prikaži na ekranu dok je fizička tastatura aktivna"</string>
- <string name="hardware" msgid="1800597768237606953">"Prikaz virtuelne tastature"</string>
+ <string name="hardware" msgid="3611039921284836033">"Koristi tastaturu na ekranu"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurirajte uređaj <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurirajte fizičke tastature"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Dodirnite da odaberete jezik i raspored"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Nedostupno: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Zahtjev za odobrenje je potisnut"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nije dostupna"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nastavite na telefonu"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon nije dostupan"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na uređaju Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Trenutno ne možete pristupiti ovoj aplikaciji na uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Umjesto toga pokušajte na telefonu."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prijenosa. Prvo dajte odobrenje na Android TV uređaju."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prijenosa. Prvo dajte odobrenje na tabletu."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Aplikacija traži dodatna odobrenja, ali se ona ne mogu dati u sesiji prijenosa. Prvo dodajte odobrenje na telefonu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na uređaju Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na tabletu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ova aplikacija zahtijeva dodatnu sigurnost. Umjesto toga pokušajte na telefonu."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nije moguće pristupiti kameri telefona s uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nije moguće pristupiti kameri tableta s uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Ovom ne možete pristupiti tokom prijenosa. Umjesto toga pokušajte na telefonu."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tokom prijenosa nije moguće gledati sliku u slici"</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistemski zadano"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Odobrenje za profil pratećeg sata da upravlja satovima"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index d86d9de..a1bbc01 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REBUTJA"</string>
<string name="select_input_method" msgid="3971267998568587025">"Selecciona un mètode d\'introducció"</string>
<string name="show_ime" msgid="6406112007347443383">"Mantén-lo en pantalla mentre el teclat físic està actiu"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostra el teclat virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Utilitza el teclat en pantalla"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configura <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configura els teclats físics"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toca per seleccionar l\'idioma i la disposició"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"L\'aplicació no està disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ara mateix, <xliff:g id="APP_NAME">%1$s</xliff:g> no està disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no està disponible"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"S\'ha suprimit la sol·licitud de permís"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"La càmera no està disponible"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continua al telèfon"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"El micròfon no està disponible"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"En aquests moments, No s\'hi pot accedir des del teu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al dispositiu Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"En aquests moments, No s\'hi pot accedir des del teu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho a la tauleta."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"No s\'hi pot accedir des del teu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al telèfon."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Aquesta aplicació requereix permisos addicionals, però els permisos no es poden concedir en una sessió de reproducció en continu. Primer concedeix el permís al teu dispositiu Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Aquesta aplicació requereix permisos addicionals, però els permisos no es poden concedir en una sessió de reproducció en continu. Primer concedeix el permís a la teva tauleta."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Aquesta aplicació requereix permisos addicionals, però els permisos no es poden concedir en una sessió de reproducció en continu. Primer concedeix el permís al teu telèfon."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Aquesta aplicació sol·licita seguretat addicional. Prova-ho al dispositiu Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Aquesta aplicació sol·licita seguretat addicional. Prova-ho a la tauleta."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Aquesta aplicació sol·licita seguretat addicional. Prova-ho al telèfon."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No es pot accedir a la càmera del telèfon des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No es pot accedir a la càmera de la tauleta des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"No s\'hi pot accedir mentre s\'està reproduint en continu. Prova-ho al telèfon."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"No es pot veure el mode d\'imatge sobre imatge durant la reproducció en continu"</string>
<string name="system_locale_title" msgid="711882686834677268">"Valor predeterminat del sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"TARGETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permís del perfil del rellotge perquè l\'aplicació complementària gestioni els rellotges"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 02d7309..069b3bc 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ODMÍTNOUT"</string>
<string name="select_input_method" msgid="3971267998568587025">"Vybrat metodu zadávání"</string>
<string name="show_ime" msgid="6406112007347443383">"Ponechat na obrazovce, když je aktivní fyzická klávesnice"</string>
- <string name="hardware" msgid="1800597768237606953">"Zobrazit virtuální klávesnici"</string>
+ <string name="hardware" msgid="3611039921284836033">"Použít softwarovou klávesnici"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Nakonfigurujte zařízení <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Nakonfigurujte fyzické klávesnice"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Klepnutím vyberte jazyk a rozvržení"</string>
@@ -1955,7 +1955,7 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> momentálně není dostupná. Tato předvolba se spravuje v aplikaci <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Další informace"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Zrušit pozastavení aplikace"</string>
- <string name="work_mode_off_title" msgid="6367463960165135829">"Zrušit pozast. prac. aplikací?"</string>
+ <string name="work_mode_off_title" msgid="6367463960165135829">"Zrušit pozastavení pracovních aplikací?"</string>
<string name="work_mode_turn_on" msgid="5316648862401307800">"Zrušit pozastavení"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Stav nouze"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikace není k dispozici"</string>
@@ -2318,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ze zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze získat přístup k fotoaparátu telefonu"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ze zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze získat přístup k fotoaparátu tabletu"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Tento obsah při streamování nelze zobrazit. Zkuste to na telefonu."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Během streamování nelze zobrazit obraz v obraze"</string>
<string name="system_locale_title" msgid="711882686834677268">"Výchozí nastavení systému"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Oprávnění profilu doprovodných hodinek ke správě hodinek"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 83edf27..f698b34 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"AFVIS"</string>
<string name="select_input_method" msgid="3971267998568587025">"Vælg inputmetode"</string>
<string name="show_ime" msgid="6406112007347443383">"Behold den på skærmen, mens det fysiske tastatur er aktivt"</string>
- <string name="hardware" msgid="1800597768237606953">"Vis virtuelt tastatur"</string>
+ <string name="hardware" msgid="3611039921284836033">"Brug skærmtastaturet"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurer <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurer fysiske tastaturer"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tryk for at vælge sprog og layout"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgængelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgængelig lige nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er ikke understøttet"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Anmodning om tilladelse blokeret"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kameraet er ikke tilgængeligt"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Fortsæt på telefonen"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonen er ikke tilgængelig"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din Android TV-enhed i stedet."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din tablet i stedet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din telefon i stedet."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Denne app anmoder om yderligere tilladelser, men der kan ikke gives tilladelser under en streamingsession. Giv tilladelse på din Android TV-enhed først."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Denne app anmoder om yderligere tilladelser, men der kan ikke gives tilladelser under en streamingsession. Giv tilladelse på din tablet først."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Denne app anmoder om yderligere tilladelser, men der kan ikke gives tilladelser under en streamingsession. Giv tilladelse på din telefon først."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Denne app anmoder om yderligere sikkerhed. Prøv på din Android TV-enhed i stedet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Denne app anmoder om yderligere sikkerhed. Prøv på din tablet i stedet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Denne app anmoder om yderligere sikkerhed. Prøv på din telefon i stedet."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kameraet på din telefon kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kameraet på din tablet kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Der er ikke adgang til dette indhold under streaming. Prøv på din telefon i stedet."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Funktionen Integreret billede er ikke tilgængelig, når der streames"</string>
<string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string>
<string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Tilladelse til at administrere ure for urprofilens medfølgende app"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 381fe71..de50e04 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ABLEHNEN"</string>
<string name="select_input_method" msgid="3971267998568587025">"Eingabemethode wählen"</string>
<string name="show_ime" msgid="6406112007347443383">"Bildschirmtastatur auch dann anzeigen, wenn physische Tastatur aktiv ist"</string>
- <string name="hardware" msgid="1800597768237606953">"Virtuelle Tastatur einblenden"</string>
+ <string name="hardware" msgid="3611039921284836033">"Bildschirmtastatur verwenden"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> konfigurieren"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Physische Tastaturen konfigurieren"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Zum Auswählen von Sprache und Layout tippen"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App ist nicht verfügbar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ist derzeit nicht verfügbar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nicht verfügbar"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Berechtigungsanfrage unterdrückt"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nicht verfügbar"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Weiter auf Smartphone"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon nicht verfügbar"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Android TV-Gerät."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Auf deinem <xliff:g id="DEVICE">%1$s</xliff:g> ist derzeit kein Zugriff möglich. Versuche es stattdessen auf deinem Smartphone."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Diese App fordert zusätzliche Berechtigungen an – in einer Streamingsitzung können jedoch keine Berechtigungen gewährt werden. Gewähre die Berechtigung zuerst auf deinem Android TV-Gerät."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Diese App fordert zusätzliche Berechtigungen an – in einer Streamingsitzung können jedoch keine Berechtigungen gewährt werden. Gewähre die Berechtigung zuerst auf deinem Tablet."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Diese App fordert zusätzliche Berechtigungen an – in einer Streamingsitzung können jedoch keine Berechtigungen gewährt werden. Gewähre die Berechtigung zuerst auf deinem Smartphone."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Diese App fordert zusätzliche Sicherheit an. Versuch es stattdessen auf deinem Android TV-Gerät."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Diese App fordert zusätzliche Sicherheit an. Versuch es stattdessen auf deinem Tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Diese App fordert zusätzliche Sicherheit an. Versuch es stattdessen auf deinem Smartphone."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Zugriff auf die Kamera des Smartphones über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Zugriff auf die Kamera des Tablets über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Während des Streamings ist kein Zugriff möglich. Versuch es stattdessen auf deinem Smartphone."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Funktion „Bild im Bild“ kann beim Streamen nicht verwendet werden"</string>
<string name="system_locale_title" msgid="711882686834677268">"Standardeinstellung des Systems"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Berechtigung für Companion-Smartwatch-Profil zum Verwalten von Smartwatches"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 90fb787..b9e447f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ΑΠΟΡΡΙΨΗ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Επιλογή μεθόδου εισόδου"</string>
<string name="show_ime" msgid="6406112007347443383">"Να παραμένει στην οθόνη όταν είναι ενεργό το κανονικό πληκτρολόγιο"</string>
- <string name="hardware" msgid="1800597768237606953">"Εμφάνιση εικονικού πληκτρολ."</string>
+ <string name="hardware" msgid="3611039921284836033">"Χρήση πληκτρολογίου οθόνης"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Διαμόρφωση <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Διαμόρφωση φυσικών πληκτρολογίων"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Πατήστε για να επιλέξετε γλώσσα και διάταξη"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> δεν διατίθεται"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Το αίτημα άδειας ανεστάλη"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Η κάμερα δεν είναι διαθέσιμη"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Συνέχεια στο τηλέφωνο"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Το μικρόφωνο δεν είναι διαθέσιμο"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στη συσκευή Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στο tablet σας."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Δεν είναι δυνατή η πρόσβαση στη συγκεκριμένη εφαρμογή από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g> αυτήν τη στιγμή. Δοκιμάστε στο τηλέφωνό σας."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Αυτή η εφαρμογή ζητά πρόσθετες άδειες, αλλά οι άδειες δεν μπορούν να παραχωρηθούν σε μια περίοδο σύνδεσης ροής. Εκχωρήστε πρώτα την άδεια στη συσκευή Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Αυτή η εφαρμογή ζητά πρόσθετες άδειες, αλλά οι άδειες δεν μπορούν να παραχωρηθούν σε μια περίοδο σύνδεσης ροής. Εκχωρήστε πρώτα την άδεια στο tablet σας."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Αυτή η εφαρμογή ζητά πρόσθετες άδειες, αλλά οι άδειες δεν μπορούν να παραχωρηθούν σε μια περίοδο σύνδεσης ροής. Εκχωρήστε πρώτα την άδεια στο τηλέφωνό σας."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Αυτή η εφαρμογή ζητά πρόσθετη ασφάλεια. Δοκιμάστε στη συσκευή Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Αυτή η εφαρμογή ζητά πρόσθετη ασφάλεια. Δοκιμάστε στο tablet σας."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Αυτή η εφαρμογή ζητά πρόσθετη ασφάλεια. Δοκιμάστε στο τηλέφωνό σας."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Δεν είναι δυνατή η πρόσβαση στην κάμερα τηλεφώνου από το <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Δεν είναι δυνατή η πρόσβαση στην κάμερα του tablet από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Δεν είναι δυνατή η πρόσβαση σε αυτό το στοιχείο κατά τη ροή. Δοκιμάστε στο τηλέφωνό σας."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Δεν είναι δυνατή η προβολή picture-in-picture κατά τη ροή"</string>
<string name="system_locale_title" msgid="711882686834677268">"Προεπιλογή συστήματος"</string>
<string name="default_card_name" msgid="9198284935962911468">"ΚΑΡΤΑ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Άδεια προφίλ συνοδευτικής εφαρμογής ρολογιού για τη διαχείριση ρολογιών"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 0caebde..b49c053 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"DECLINE"</string>
<string name="select_input_method" msgid="3971267998568587025">"Choose input method"</string>
<string name="show_ime" msgid="6406112007347443383">"Keep it on screen while physical keyboard is active"</string>
- <string name="hardware" msgid="1800597768237606953">"Show virtual keyboard"</string>
+ <string name="hardware" msgid="3611039921284836033">"Use on-screen keyboard"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure physical keyboards"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tap to select language and layout"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Permission request suppressed"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Camera unavailable"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continue on phone"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microphone unavailable"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your Android TV device first."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your tablet first."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your phone first."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"This app is requesting additional security. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"This app is requesting additional security. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"This app is requesting additional security. Try on your phone instead."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"System default"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion watch profile permission to manage watches"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 44741f5..84c1492 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"DECLINE"</string>
<string name="select_input_method" msgid="3971267998568587025">"Choose input method"</string>
<string name="show_ime" msgid="6406112007347443383">"Keep it on screen while physical keyboard is active"</string>
- <string name="hardware" msgid="1800597768237606953">"Show virtual keyboard"</string>
+ <string name="hardware" msgid="3611039921284836033">"Use on-screen keyboard"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure physical keyboards"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tap to select language and layout"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"System default"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion Watch profile permission to manage watches"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 278422f..318324a 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"DECLINE"</string>
<string name="select_input_method" msgid="3971267998568587025">"Choose input method"</string>
<string name="show_ime" msgid="6406112007347443383">"Keep it on screen while physical keyboard is active"</string>
- <string name="hardware" msgid="1800597768237606953">"Show virtual keyboard"</string>
+ <string name="hardware" msgid="3611039921284836033">"Use on-screen keyboard"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure physical keyboards"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tap to select language and layout"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Permission request suppressed"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Camera unavailable"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continue on phone"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microphone unavailable"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your Android TV device first."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your tablet first."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your phone first."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"This app is requesting additional security. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"This app is requesting additional security. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"This app is requesting additional security. Try on your phone instead."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"System default"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion watch profile permission to manage watches"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index ee8e488..2d75eae 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"DECLINE"</string>
<string name="select_input_method" msgid="3971267998568587025">"Choose input method"</string>
<string name="show_ime" msgid="6406112007347443383">"Keep it on screen while physical keyboard is active"</string>
- <string name="hardware" msgid="1800597768237606953">"Show virtual keyboard"</string>
+ <string name="hardware" msgid="3611039921284836033">"Use on-screen keyboard"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure physical keyboards"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tap to select language and layout"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is not available"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not available right now."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> unavailable"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Permission request suppressed"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Camera unavailable"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continue on phone"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microphone unavailable"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"This can’t be accessed on your <xliff:g id="DEVICE">%1$s</xliff:g> at this time. Try on your phone instead."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your Android TV device first."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your tablet first."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"This app is requesting additional permissions, but permissions can\'t be granted in a streaming session. Grant the permission on your phone first."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"This app is requesting additional security. Try on your Android TV device instead."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"This app is requesting additional security. Try on your tablet instead."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"This app is requesting additional security. Try on your phone instead."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"System default"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion watch profile permission to manage watches"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index f67c0d0..e544c1c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"DECLINE"</string>
<string name="select_input_method" msgid="3971267998568587025">"Choose input method"</string>
<string name="show_ime" msgid="6406112007347443383">"Keep it on screen while physical keyboard is active"</string>
- <string name="hardware" msgid="1800597768237606953">"Show virtual keyboard"</string>
+ <string name="hardware" msgid="3611039921284836033">"Use on-screen keyboard"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure physical keyboards"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tap to select language and layout"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Can’t access the phone’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Can’t access the tablet’s camera from your <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"This can’t be accessed while streaming. Try on your phone instead."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Can’t view picture-in-picture while streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"System default"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Companion Watch profile permission to manage watches"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 112dbda..c6ab2f1 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RECHAZAR"</string>
<string name="select_input_method" msgid="3971267998568587025">"Selecciona el método de entrada"</string>
<string name="show_ime" msgid="6406112007347443383">"Mientras el teclado físico está activo"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostrar teclado virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Usar teclado en pantalla"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configura <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configura teclados físicos"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Presiona para seleccionar el idioma y el diseño"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"La app no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible en este momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Se rechazó la solicitud de permiso"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"La cámara no está disponible"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continúa en el teléfono"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"El micrófono no está disponible"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Por el momento, no se puede acceder a esto en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Inténtalo en tu teléfono."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Esta app solicita permisos adicionales, pero estos no se pueden otorgar durante una sesión de transmisión. Primero, otorga el permiso en el dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Esta app solicita permisos adicionales, pero estos no se pueden otorgar durante una sesión de transmisión. Primero, otorga el permiso en la tablet."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Esta app solicita permisos adicionales, pero estos no se pueden otorgar durante una sesión de transmisión. Primero, otorga el permiso en el teléfono."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta app solicita seguridad adicional. Inténtalo en tu dispositivo Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esta app solicita seguridad adicional. Inténtalo en tu tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esta app solicita seguridad adicional. Inténtalo en tu teléfono."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del dispositivo desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara de la tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una transmisión. Inténtalo en tu teléfono."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"No puedes ver pantalla en pantalla mientras transmites"</string>
<string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"TARJETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permiso de perfil del reloj complementario para administrar relojes"</string>
@@ -2345,9 +2340,9 @@
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desactivar"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"Se configuró <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%s</xliff:g>. Presiona para cambiar esta opción."</string>
- <string name="keyboard_layout_notification_two_selected_message" msgid="1876349944065922950">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%1$s</xliff:g> y <xliff:g id="LAYOUT_2">%2$s</xliff:g>. Presiona para cambiar esta opción."</string>
- <string name="keyboard_layout_notification_three_selected_message" msgid="280734264593115419">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g> y <xliff:g id="LAYOUT_3">%3$s</xliff:g>. Presiona para cambiar esta opción."</string>
- <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g> y <xliff:g id="LAYOUT_3">%3$s</xliff:g>. Presiona para cambiarlo."</string>
+ <string name="keyboard_layout_notification_two_selected_message" msgid="1876349944065922950">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>. Presiona para cambiar esta opción."</string>
+ <string name="keyboard_layout_notification_three_selected_message" msgid="280734264593115419">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>. Presiona para cambiar esta opción."</string>
+ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Diseño de teclado establecido en <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>. Presiona para cambiar esta opción."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclados físicos configurados"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Presiona para ver los teclados"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e25f770..3803005 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RECHAZAR"</string>
<string name="select_input_method" msgid="3971267998568587025">"Selecciona un método de entrada"</string>
<string name="show_ime" msgid="6406112007347443383">"Mantenlo en pantalla mientras el teclado físico está activo"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostrar teclado virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Usar teclado en pantalla"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configura <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configura teclados físicos"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toca para seleccionar el idioma y el diseño"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"La aplicación no está disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"En estos momentos, <xliff:g id="APP_NAME">%1$s</xliff:g> no está disponible."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> no disponible"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Solicitud de permiso rechazada"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Cámara no disponible"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continúa en el teléfono"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Micrófono no disponible"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"En estos momentos, no se puede acceder a este contenido en tu <xliff:g id="DEVICE">%1$s</xliff:g>. Prueba en tu teléfono."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Esta aplicación está solicitando permisos adicionales, pero no se pueden dar durante una sesión de streaming. Da primero el permiso en tu dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Esta aplicación está solicitando permisos adicionales, pero no se pueden dar durante una sesión de streaming. Da primero el permiso en tu tablet."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Esta aplicación está solicitando permisos adicionales, pero no se pueden dar durante una sesión de streaming. Da primero el permiso en tu teléfono."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta aplicación solicita seguridad adicional. Prueba en tu dispositivo Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esta aplicación solicita seguridad adicional. Prueba en tu tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esta aplicación solicita seguridad adicional. Prueba en tu teléfono."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del teléfono desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara del tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una emisión. Prueba en tu teléfono."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"No se puede usar imagen en imagen mientras se emite contenido"</string>
<string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"TARJETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permiso del perfil del reloj complementario para gestionar relojes"</string>
@@ -2345,8 +2340,8 @@
<string name="device_state_notification_turn_off_button" msgid="6327161707661689232">"Desactivar"</string>
<string name="keyboard_layout_notification_selected_title" msgid="1202560174252421219">"<xliff:g id="DEVICE_NAME">%s</xliff:g> configurado"</string>
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%s</xliff:g>. Toca para cambiarlo."</string>
- <string name="keyboard_layout_notification_two_selected_message" msgid="1876349944065922950">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g> y <xliff:g id="LAYOUT_2">%2$s</xliff:g>. Toca para cambiarlo."</string>
- <string name="keyboard_layout_notification_three_selected_message" msgid="280734264593115419">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g> y <xliff:g id="LAYOUT_3">%3$s</xliff:g>. Toca para cambiarlo."</string>
+ <string name="keyboard_layout_notification_two_selected_message" msgid="1876349944065922950">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>. Toca para cambiarlo."</string>
+ <string name="keyboard_layout_notification_three_selected_message" msgid="280734264593115419">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>. Toca para cambiarlo."</string>
<string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"Diseño del teclado definido como <xliff:g id="LAYOUT_1">%1$s</xliff:g>, <xliff:g id="LAYOUT_2">%2$s</xliff:g>, <xliff:g id="LAYOUT_3">%3$s</xliff:g>… Toca para cambiarlo."</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"Teclados físicos configurados"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"Toca para ver los teclados"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index a64b140..8bb1f16 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"KEELDU"</string>
<string name="select_input_method" msgid="3971267998568587025">"Valige sisestusmeetod"</string>
<string name="show_ime" msgid="6406112007347443383">"Hoia seda ekraanil, kui füüsiline klaviatuur on aktiivne"</string>
- <string name="hardware" msgid="1800597768237606953">"Virtuaalse klaviatuuri kuvam."</string>
+ <string name="hardware" msgid="3611039921284836033">"Kasuta ekraaniklaviatuuri"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Seadistage <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Seadistage füüsilised klaviatuurid"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Puudutage keele ja paigutuse valimiseks"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Rakendus ei ole saadaval"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole praegu saadaval."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei ole saadaval"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Loataotlus peideti"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kaamera pole saadaval"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Jätkake telefonis"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon pole saadaval"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma Android TV seadmega."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma tahvelarvutiga."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Sellele ei pääse praegu teie seadmega (<xliff:g id="DEVICE">%1$s</xliff:g>) juurde. Proovige juurde pääseda oma telefoniga."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"See rakendus taotleb lisalube, kuid lube ei saa voogesituse seansis anda. Kõigepealt andke luba oma Android TV seadmele."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"See rakendus taotleb lisalube, kuid lube ei saa voogesituse seansis anda. Kõigepealt andke luba oma tahvelarvutile."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"See rakendus taotleb lisalube, kuid lube ei saa voogesituse seansis anda. Kõigepealt andke luba oma telefonile."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"See rakendus nõuab lisaturvalisust. Proovige juurde pääseda oma Android TV seadmes."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"See rakendus nõuab lisaturvalisust. Proovige juurde pääseda oma tahvelarvutis."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"See rakendus nõuab lisaturvalisust. Proovige juurde pääseda oma telefonis."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse telefoni kaamerale juurde."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tahvelarvuti kaamerale juurde"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Sellele ei pääse voogesituse ajal juurde. Proovige juurde pääseda oma telefonis."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Voogesitamise ajal ei saa pilt pildis funktsiooni kasutada"</string>
<string name="system_locale_title" msgid="711882686834677268">"Süsteemi vaikeseade"</string>
<string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kaasrakenduse profiili luba kellade haldamiseks"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d9c97c6..a5a3a2c 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"BAZTERTU"</string>
<string name="select_input_method" msgid="3971267998568587025">"Aukeratu idazketa-metodoa"</string>
<string name="show_ime" msgid="6406112007347443383">"Erakutsi pantailan teklatu fisikoa aktibo dagoen bitartean"</string>
- <string name="hardware" msgid="1800597768237606953">"Erakutsi teklatu birtuala"</string>
+ <string name="hardware" msgid="3611039921284836033">"Erabili pantailako teklatua"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfiguratu <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfiguratu teklatu fisikoak"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Hizkuntza eta diseinua hautatzeko, sakatu hau"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ezin da atzitu telefonoaren kamera <xliff:g id="DEVICE">%1$s</xliff:g> gailutik"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ezin da atzitu tabletaren kamera <xliff:g id="DEVICE">%1$s</xliff:g> gailutik"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Ezin da atzitu edukia hura igorri bitartean. Oraingo gailuaren ordez, erabili telefonoa."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Edukia zuzenean erreproduzitu bitartean ezin da pantaila txiki gainjarrian ikusi"</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistemaren balio lehenetsia"</string>
<string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g> TXARTELA"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Aplikazio osagarrien erloju-profilaren baimena erlojuak kudeatzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 52cf5e0..439226d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -393,7 +393,7 @@
<string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"به برنامه امکان میدهد به فرآیندهای پسزمینه سایر برنامهها پایان دهد. این ممکن است باعث شود سایر برنامهها متوقف شوند."</string>
<string name="permlab_systemAlertWindow" msgid="5757218350944719065">"این برنامه میتواند روی برنامههای دیگر ظاهر شود"</string>
<string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"این برنامه میتواند روی برنامههای دیگر یا سایر قسمتهای صفحه ظاهر شود. ممکن است در عملکرد معمول برنامههای دیگر اختلال ایجاد کند و شیوه نمایش آنها را تغییر دهد."</string>
- <string name="permlab_hideOverlayWindows" msgid="6382697828482271802">"پنهان کردن همپوشانی برنامههای دیگر"</string>
+ <string name="permlab_hideOverlayWindows" msgid="6382697828482271802">"پنهان کردن رونهاد برنامههای دیگر"</string>
<string name="permdesc_hideOverlayWindows" msgid="5660242821651958225">"این برنامه میتواند از سیستم بخواهد تا همپوشانیهای ایجادشده توسط برنامههای دیگر را روی برنامه نشان ندهد."</string>
<string name="permlab_runInBackground" msgid="541863968571682785">"اجرا شدن در پسزمینه"</string>
<string name="permdesc_runInBackground" msgid="4344539472115495141">"این برنامه میتواند در پسزمینه اجرا شود. ممکن است شارژ باتری زودتر مصرف شود."</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"نپذیرفتن"</string>
<string name="select_input_method" msgid="3971267998568587025">"انتخاب روش ورودی"</string>
<string name="show_ime" msgid="6406112007347443383">"وقتی صفحهکلید فیزیکی فعال است این ویرایشگر را روی صفحه نگهمیدارد"</string>
- <string name="hardware" msgid="1800597768237606953">"نمایش صفحهکلید مجازی"</string>
+ <string name="hardware" msgid="3611039921284836033">"استفاده از صفحهکلید مجازی"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"پیکربندی <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"پیکربندی صفحهکلیدهای فیزیکی"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"برای انتخاب زبان و چیدمان ضربه بزنید"</string>
@@ -1642,7 +1642,7 @@
<string name="media_route_status_in_use" msgid="6684112905244944724">"در حال استفاده"</string>
<string name="display_manager_built_in_display_name" msgid="1015775198829722440">"صفحه نمایش از خود"</string>
<string name="display_manager_hdmi_display_name" msgid="1022758026251534975">"صفحه HDMI"</string>
- <string name="display_manager_overlay_display_name" msgid="5306088205181005861">"همپوشانی #<xliff:g id="ID">%1$d</xliff:g>"</string>
+ <string name="display_manager_overlay_display_name" msgid="5306088205181005861">"رونهاد #<xliff:g id="ID">%1$d</xliff:g>"</string>
<string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
<string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">"، امن"</string>
<string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"الگو را فراموش کردهاید"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"برنامه در دسترس نیست"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> درحالحاضر در دسترس نیست."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دردسترس نیست"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"درخواست اجازه رد شد"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"دوربین دردسترس نیست"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ادامه دادن در تلفن"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"میکروفون دردسترس نیست"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"درحالحاضر نمیتوان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در دستگاه Android TV امتحان کنید."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"درحالحاضر نمیتوان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در رایانه لوحیتان امتحان کنید."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"درحالحاضر نمیتوان در <xliff:g id="DEVICE">%1$s</xliff:g> شما به این برنامه دسترسی داشت. دسترسی به آن را در تلفنتان امتحان کنید."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"این برنامه درخواست اجازههای اضافی دارد، اما امکان دادن این اجازهها در جلسه جاریسازی وجود ندارد. ابتدا اجازه را در دستگاه Android TV مجاز کنید."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"این برنامه درخواست اجازههای اضافی دارد، اما امکان دادن این اجازهها در جلسه جاریسازی وجود ندارد. ابتدا اجازه را در رایانه لوحیتان مجاز کنید."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"این برنامه درخواست اجازههای اضافی دارد، اما امکان دادن این اجازهها در جلسه جاریسازی وجود ندارد. ابتدا اجازه را در تلفنتان مجاز کنید."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"این برنامه درخواست امنیت اضافی دارد. دسترسی به آن را در دستگاه Android TV امتحان کنید."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"این برنامه درخواست امنیت اضافی دارد. دسترسی به آن را در رایانه لوحیتان امتحان کنید."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"این برنامه درخواست امنیت اضافی دارد. دسترسی به آن را در تلفنتان امتحان کنید."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"از <xliff:g id="DEVICE">%1$s</xliff:g> به دوربین تلفن دسترسی ندارید"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"نمیتوان از <xliff:g id="DEVICE">%1$s</xliff:g> شما به دوربین رایانه لوحی دسترسی داشت"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"درحین جاریسازی، نمیتوانید به آن دسترسی داشته باشید. دسترسی به آن را در تلفنتان امتحان کنید."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"هنگام جاریسازی نمیتوان تصویر در تصویر را مشاهده کرد"</string>
<string name="system_locale_title" msgid="711882686834677268">"پیشفرض سیستم"</string>
<string name="default_card_name" msgid="9198284935962911468">"کارت <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"اجازه نمایه «ساعت همراه» برای مدیریت ساعتها"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7b9c023..1c425af 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"HYLKÄÄ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Valitse syöttötapa"</string>
<string name="show_ime" msgid="6406112007347443383">"Pidä näytöllä, kun fyysinen näppäimistö on aktiivinen"</string>
- <string name="hardware" msgid="1800597768237606953">"Näytä virtuaalinen näppäimistö"</string>
+ <string name="hardware" msgid="3611039921284836033">"Käytä näyttönäppäimistöä"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Määritä <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Määritä fyysiset näppäimistöt"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Valitse kieli ja asettelu koskettamalla."</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Sovellus ei ole käytettävissä"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei ole nyt käytettävissä."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ei käytettävissä"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Lupapyyntö estetty"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera ei käytettävissä"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Jatka puhelimella"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofoni ei ole käytettävissä"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta Android TV ‑laitteella."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta tabletilla."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"<xliff:g id="DEVICE">%1$s</xliff:g> ei tällä hetkellä saa pääsyä sovellukseen. Kokeile striimausta puhelimella."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Sovellus pyytää lisälupia, mutta lupia ei voi myöntää striimatessa. Myönnä lupa ensin Android TV ‑laitteella."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Sovellus pyytää lisälupia, mutta lupia ei voi myöntää striimatessa. Myönnä lupa ensin tabletilla."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Sovellus pyytää lisälupia, mutta lupia ei voi myöntää striimatessa. Myönnä lupa ensin puhelimella."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Sovellus pyytää lisäsuojausta. Kokeile striimausta Android TV ‑laitteella."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Sovellus pyytää lisäsuojausta. Kokeile striimausta tabletilla."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Sovellus pyytää lisäsuojausta. Kokeile striimausta puhelimella."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse puhelimen kameraan"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tabletin kameraan"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Sisältöön ei saa pääsyä striimauksen aikana. Kokeile striimausta puhelimella."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Pikkuruutua ei voi nähdä striimauksen aikana"</string>
<string name="system_locale_title" msgid="711882686834677268">"Järjestelmän oletusarvo"</string>
<string name="default_card_name" msgid="9198284935962911468">"Kortti: <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kumppanin kelloprofiilin hallintalupa"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index fdd3802..c4fa226 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REFUSER"</string>
<string name="select_input_method" msgid="3971267998568587025">"Sélectionnez le mode de saisie"</string>
<string name="show_ime" msgid="6406112007347443383">"Afficher lorsque le clavier physique est activé"</string>
- <string name="hardware" msgid="1800597768237606953">"Afficher le clavier virtuel"</string>
+ <string name="hardware" msgid="3611039921284836033">"Utiliser le clavier à l\'écran"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configurer <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configurer les claviers physiques"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Touchez pour sélectionner la langue et la configuration du clavier"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"L\'application n\'est pas accessible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas accessible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non accessible"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"La demande d\'autorisation a été supprimée."</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Appareil photo non accessible"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuer sur le téléphone"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microphone non accessible"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre appareil Android TV à la place."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre tablette à la place."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre téléphone à la place."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Cette application demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre appareil Android TV d\'abord."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Cette application demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre tablette d\'abord."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Cette application demande des autorisations supplémentaires, mais les autorisations ne peuvent pas être accordées lors d\'une session de diffusion en continu. Accordez l\'autorisation sur votre téléphone d\'abord."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Cette application demande une sécurité supplémentaire. Essayez sur votre appareil Android TV à la place."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Cette application demande une sécurité supplémentaire. Essayez sur votre tablette à la place."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Cette application demande une sécurité supplémentaire. Essayez sur votre téléphone à la place."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Vous ne pouvez pas y accéder lorsque vous utilisez la diffusion en continu. Essayez sur votre téléphone à la place."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossible d\'afficher des incrustations d\'image pendant une diffusion en continu"</string>
<string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorisation du profil de la montre de l\'application compagnon pour gérer les montres"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c0c6695..0495ce4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REFUSER"</string>
<string name="select_input_method" msgid="3971267998568587025">"Sélectionnez le mode de saisie"</string>
<string name="show_ime" msgid="6406112007347443383">"Afficher le clavier virtuel même lorsque le clavier physique est actif"</string>
- <string name="hardware" msgid="1800597768237606953">"Afficher le clavier virtuel"</string>
+ <string name="hardware" msgid="3611039921284836033">"Utiliser le clavier à l\'écran"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configurer <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configurez les claviers physiques"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Appuyez pour sélectionner la langue et la disposition"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Application non disponible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas disponible pour le moment."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponible"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Demande d\'autorisation supprimée"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Caméra indisponible"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuez sur le téléphone"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Micro indisponible"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre appareil Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre tablette."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Actuellement, vous ne pouvez pas accéder à cette application sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez plutôt d\'y accéder sur votre téléphone."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Cette appli demande des autorisations supplémentaires, mais il est impossible d\'accorder des autorisations lors d\'une session de streaming. Accordez tout d\'abord l\'autorisation sur votre appareil Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Cette appli demande des autorisations supplémentaires, mais il est impossible d\'accorder des autorisations lors d\'une session de streaming. Accordez tout d\'abord l\'autorisation sur votre tablette."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Cette appli demande des autorisations supplémentaires, mais il est impossible d\'accorder des autorisations lors d\'une session de streaming. Accordez tout d\'abord l\'autorisation sur votre téléphone."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Cette appli demande une sécurité supplémentaire. Essayez plutôt d\'y accéder sur votre appareil Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Cette appli demande une sécurité supplémentaire. Essayez plutôt d\'y accéder sur votre tablette."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Cette appli demande une sécurité supplémentaire. Essayez plutôt d\'y accéder sur votre téléphone."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Impossible d\'accéder à cela pendant le streaming. Essayez plutôt sur votre téléphone."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossible d\'afficher Picture-in-picture pendant le streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorisation du profil de la montre associée pour gérer des montres"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 31034f5..70f4355 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ANULAR"</string>
<string name="select_input_method" msgid="3971267998568587025">"Escoller método de introdución de texto"</string>
<string name="show_ime" msgid="6406112007347443383">"Móstrase na pantalla mentres o teclado físico estea activo"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostrar teclado virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Utilizar o teclado en pantalla"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configura o teclado (<xliff:g id="DEVICE_NAME">%s</xliff:g>)"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configura os teclados físicos"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toca para seleccionar o idioma e o deseño"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"A aplicación non está dispoñible"</string>
<string name="app_blocked_message" msgid="542972921087873023">"A aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> non está dispoñible neste momento."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non está dispoñible"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Eliminouse a solicitude de permiso"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"A cámara non está dispoñible"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continúa no teléfono"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"O micrófono non está dispoñible"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde a tableta."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o teléfono."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Esta aplicación solicita permisos adicionais, pero non se poden conceder nunha sesión de reprodución en tempo real. Primeiro tes que conceder o permiso no teu dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Esta aplicación solicita permisos adicionais, pero non se poden conceder nunha sesión de reprodución en tempo real. Primeiro tes que conceder o permiso na túa tableta."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Esta aplicación solicita permisos adicionais, pero non se poden conceder nunha sesión de reprodución en tempo real. Primeiro tes que conceder o permiso no teu teléfono."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta aplicación solicita seguranza adicional. Proba a facelo desde o dispositivo Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esta aplicación solicita seguranza adicional. Proba a facelo desde a tableta."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esta aplicación solicita seguranza adicional. Proba a facelo desde o teléfono."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Non se puido acceder á cámara do teléfono desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Non se puido acceder á cámara da tableta desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Non se puido acceder a este contido durante a reprodución en tempo real. Téntao desde o teléfono."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Non se pode ver un vídeo en pantalla superposta mentres se reproduce en tempo real"</string>
<string name="system_locale_title" msgid="711882686834677268">"Opción predeterminada do sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"TARXETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permiso de perfil de Companion Watch para xestionar reloxos"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 5ef4ffc..8a47646 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"નકારો"</string>
<string name="select_input_method" msgid="3971267998568587025">"ઇનપુટ પદ્ધતિ પસંદ કરો"</string>
<string name="show_ime" msgid="6406112007347443383">"જ્યારે ભૌતિક કીબોર્ડ સક્રિય હોય ત્યારે તેને સ્ક્રીન પર રાખો"</string>
- <string name="hardware" msgid="1800597768237606953">"વર્ચ્યુઅલ કીબોર્ડ બતાવો"</string>
+ <string name="hardware" msgid="3611039921284836033">"ઑન-સ્ક્રીન કીબોર્ડનો ઉપયોગ કરો"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g>ની ગોઠવણી કરો"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ભૌતિક કીબોર્ડની ગોઠવણી કરો"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ભાષા અને લેઆઉટ પસંદ કરવા માટે ટૅપ કરો"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ઉપલબ્ધ નથી"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"પરવાનગીની વિનંતી નકારવામાં આવી"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"કૅમેરા ઉપલબ્ધ નથી"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ફોન પર ચાલુ રાખો"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"માઇક્રોફોન ઉપલબ્ધ નથી"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા Android TV ડિવાઇસ પર પ્રયાસ કરો."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા ટૅબ્લેટ પર પ્રયાસ કરો."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"અત્યારે આને તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પર ઍક્સેસ કરી શકાતી નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"આ ઍપ વધારાની પરવાનગીઓની વિનંતી કરી રહી છે પણ સ્ટ્રીમિંગ સત્રમાં પરવાનગીઓને મંજૂરી આપી શકાતી નથી. પહેલા તમારા Android TV ડિવાઇસ પર પરવાનગીની મંજૂરી આપો."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"આ ઍપ વધારાની પરવાનગીઓની વિનંતી કરી રહી છે પણ સ્ટ્રીમિંગ સત્રમાં પરવાનગીઓને મંજૂરી આપી શકાતી નથી. પહેલા તમારા ટૅબ્લેટ પર પરવાનગીની મંજૂરી આપો."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"આ ઍપ વધારાની પરવાનગીઓની વિનંતી કરી રહી છે પણ સ્ટ્રીમિંગ સત્રમાં પરવાનગીઓને મંજૂરી આપી શકાતી નથી. પહેલા તમારા ફોન પર પરવાનગીની મંજૂરી આપો."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"આ ઍપ દ્વારા વધારાની સુરક્ષાની વિનંતી કરવામાં આવી રહી છે. તેના બદલે તમારા Android TV ડિવાઇસ પર પ્રયાસ કરો."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"આ ઍપ દ્વારા વધારાની સુરક્ષાની વિનંતી કરવામાં આવી રહી છે. તેના બદલે તમારા ટૅબ્લેટ પર પ્રયાસ કરો."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"આ ઍપ દ્વારા વધારાની સુરક્ષાની વિનંતી કરવામાં આવી રહી છે. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ફોનના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ટૅબ્લેટના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"સ્ટ્રીમ કરતી વખતે આ ઍક્સેસ કરી શકાતું નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"સ્ટ્રીમ કરતી વખતે ચિત્ર-માં-ચિત્ર જોઈ શકતા નથી"</string>
<string name="system_locale_title" msgid="711882686834677268">"સિસ્ટમ ડિફૉલ્ટ"</string>
<string name="default_card_name" msgid="9198284935962911468">"કાર્ડ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"વૉચ મેનેજ કરવા માટે સાથી વૉચ પ્રોફાઇલની પરવાનગી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1155a2a..b6b18ec 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"अस्वीकार करें"</string>
<string name="select_input_method" msgid="3971267998568587025">"इनपुट का तरीका चुनें"</string>
<string name="show_ime" msgid="6406112007347443383">"सामान्य कीबोर्ड के सक्रिय होने के दौरान इसे स्क्रीन पर बनाए रखें"</string>
- <string name="hardware" msgid="1800597768237606953">"वर्चुअल कीबोर्ड दिखाएं"</string>
+ <string name="hardware" msgid="3611039921284836033">"ऑन-स्क्रीन कीबोर्ड इस्तेमाल करें"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> को कॉन्फ़िगर करें"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"फ़िज़िकल कीबोर्ड को कॉन्फ़िगर करें"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"भाषा और लेआउट चुनने के लिए टैप करें"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ऐप्लिकेशन उपलब्ध नहीं है"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> इस समय उपलब्ध नहीं है."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध नहीं है"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"अनुमति के अनुरोध को अस्वीकार किया गया"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"कैमरा उपलब्ध नहीं है"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"फ़ोन पर जारी रखें"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"माइक्रोफ़ोन उपलब्ध नहीं है"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने Android TV डिवाइस पर कोशिश करें."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने टैबलेट पर कोशिश करें."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने फ़ोन पर कोशिश करें."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"यह ऐप्लिकेशन ज़्यादा अनुमतियों का अनुरोध कर रहा है. हालांकि, स्ट्रीमिंग सेशन के दौरान अनुमतियां नहीं दी जा सकतीं. सबसे पहले अपने Android TV डिवाइस पर अनुमति दें."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"यह ऐप्लिकेशन ज़्यादा अनुमतियों का अनुरोध कर रहा है. हालांकि, स्ट्रीमिंग सेशन के दौरान अनुमतियां नहीं दी जा सकतीं. सबसे पहले अपने टैबलेट पर अनुमति दें."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"यह ऐप्लिकेशन ज़्यादा अनुमतियों का अनुरोध कर रहा है. हालांकि, स्ट्रीमिंग सेशन के दौरान अनुमतियां नहीं दी जा सकतीं. सबसे पहले अपने फ़ोन पर अनुमति दें."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"यह ऐप्लिकेशन ज़्यादा सुरक्षा का अनुरोध कर रहा है. इसके बजाय, अपने Android TV डिवाइस पर ऐक्सेस करने की कोशिश करें."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"यह ऐप्लिकेशन ज़्यादा सुरक्षा का अनुरोध कर रहा है. इसके बजाय, अपने टैबलेट पर ऐक्सेस करने की कोशिश करें."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"यह ऐप्लिकेशन ज़्यादा सुरक्षा का अनुरोध कर रहा है. इसके बजाय, अपने फ़ोन पर ऐक्सेस करने की कोशिश करें."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"आपके <xliff:g id="DEVICE">%1$s</xliff:g> से फ़ोन के कैमरे को ऐक्सेस नहीं किया जा सकता"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"आपके <xliff:g id="DEVICE">%1$s</xliff:g> से टैबलेट के कैमरे को ऐक्सेस नहीं किया जा सकता"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रीमिंग के दौरान, इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने फ़ोन पर ऐक्सेस करके देखें."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रीमिंग करते समय, \'पिक्चर में पिक्चर\' सुविधा इस्तेमाल नहीं की जा सकती"</string>
<string name="system_locale_title" msgid="711882686834677268">"सिस्टम डिफ़ॉल्ट"</string>
<string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"स्मार्टवॉच मैनेज करने के लिए, स्मार्टवॉच के साथ काम करने वाले साथी ऐप्लिकेशन पर प्रोफ़ाइल से जुड़ी अनुमति"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index ffda001..106d85c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ODBIJ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Odabir načina unosa"</string>
<string name="show_ime" msgid="6406112007347443383">"Zadrži na zaslonu dok je fizička tipkovnica aktivna"</string>
- <string name="hardware" msgid="1800597768237606953">"Prikaži virtualnu tipkovnicu"</string>
+ <string name="hardware" msgid="3611039921284836033">"Upotreba zaslonske tipkovnice"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurirajte uređaj <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurirajte fizičke tipkovnice"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Dodirnite da biste odabrali jezik i raspored"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija nije dostupna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutačno nije dostupna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – nije dostupno"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Upit za dopuštenje je spriječen"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nije dostupna"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nastavite na telefonu"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon nije dostupan"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na Android TV uređaju."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Trenutačno toj aplikaciji nije moguće pristupiti na vašem uređaju <xliff:g id="DEVICE">%1$s</xliff:g>. Pokušajte joj pristupiti na telefonu."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Aplikacija zahtijeva dodatna dopuštenja, no dopuštenja se ne mogu odobriti u sesiji streaminga. Dopuštenje najprije odobrite na Android TV uređaju."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Aplikacija zahtijeva dodatna dopuštenja, no dopuštenja se ne mogu odobriti u sesiji streaminga. Dopuštenje najprije odobrite na tabletu."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Aplikacija zahtijeva dodatna dopuštenja, no dopuštenja se ne mogu odobriti u sesiji streaminga. Dopuštenje najprije odobrite na telefonu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ta aplikacija zahtijeva dodatnu sigurnost. Pokušajte joj pristupiti na Android TV uređaju."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ta aplikacija zahtijeva dodatnu sigurnost. Pokušajte joj pristupiti na tabletu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ta aplikacija zahtijeva dodatnu sigurnost. Pokušajte joj pristupiti na telefonu."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"S vašeg uređaja <xliff:g id="DEVICE">%1$s</xliff:g> nije moguće pristupiti fotoaparatu telefona"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"S vašeg uređaja <xliff:g id="DEVICE">%1$s</xliff:g> nije moguće pristupiti fotoaparatu tableta"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Sadržaju nije moguće pristupiti tijekom streaminga. Pokušajte mu pristupiti na telefonu."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Slika u slici ne može se prikazivati tijekom streaminga"</string>
<string name="system_locale_title" msgid="711882686834677268">"Zadane postavke sustava"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Dopuštenje profila popratne aplikacije sata za upravljanje satovima"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 31a99ae..357c3d3 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ELUTASÍTÁS"</string>
<string name="select_input_method" msgid="3971267998568587025">"Beviteli mód kiválasztása"</string>
<string name="show_ime" msgid="6406112007347443383">"Maradjon a képernyőn, amíg a billentyűzet aktív"</string>
- <string name="hardware" msgid="1800597768237606953">"Virtuális billentyűzet"</string>
+ <string name="hardware" msgid="3611039921284836033">"Képernyő-billentyűzet"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"A(z) <xliff:g id="DEVICE_NAME">%s</xliff:g> beállítása"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Fizikai billentyűzetek beállítása"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Koppintson a nyelv és a billentyűzetkiosztás kiválasztásához"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nem lehet hozzáférni a telefon kamerájához a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nem lehet hozzáférni a táblagép kamerájához a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Ehhez a tartalomhoz nem lehet hozzáférni streamelés közben. Próbálja újra a telefonján."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Streamelés közben nem lehetséges a kép a képben módban való lejátszás"</string>
<string name="system_locale_title" msgid="711882686834677268">"Rendszerbeállítás"</string>
<string name="default_card_name" msgid="9198284935962911468">"KÁRTYA: <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Társóra-profilra vonatkozó engedély az órák kezeléséhez"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index fd4f9e6..9b20543 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ՄԵՐԺԵԼ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Ընտրեք ներածման եղանակը"</string>
<string name="show_ime" msgid="6406112007347443383">"Պահել էկրանին, երբ ֆիզիկական ստեղնաշարն ակտիվ է"</string>
- <string name="hardware" msgid="1800597768237606953">"Ցույց տալ վիրտուալ ստեղնաշարը"</string>
+ <string name="hardware" msgid="3611039921284836033">"Օգտագործել էկրանային ստեղնաշար"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Կարգավորեք <xliff:g id="DEVICE_NAME">%s</xliff:g> սարքը"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Կարգավորեք ֆիզիկական ստեղնաշարերը"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Հպեք՝ լեզուն և դասավորությունն ընտրելու համար"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Հավելվածը հասանելի չէ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածն այս պահին հասանելի չէ։"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g>՝ անհասանելի է"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Թույլտվության հայտն արգելափակվել է"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Տեսախցիկն անհասանելի է"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Շարունակեք հեռախոսով"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Խոսափողն անհասանելի է"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք Android TV սարքում։"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք ձեր պլանշետում։"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Այս պահին հնարավոր չէ բացել հավելվածը <xliff:g id="DEVICE">%1$s</xliff:g> սարքում։ Փորձեք ձեր հեռախոսում։"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Այս հավելվածը պահանջում է լրացուցիչ թույլտվություններ, սակայն դրանք հնարավոր չէ տրամադրել հեռարձակման ժամանակ։ Նախ տրամադրեք թույլտվությունը ձեր Android TV սարքում։"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Այս հավելվածը պահանջում է լրացուցիչ թույլտվություններ, սակայն դրանք հնարավոր չէ տրամադրել հեռարձակման ժամանակ։ Նախ տրամադրեք թույլտվությունը ձեր պլանշետում։"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Այս հավելվածը պահանջում է լրացուցիչ թույլտվություններ, սակայն դրանք հնարավոր չէ տրամադրել հեռարձակման ժամանակ։ Նախ տրամադրեք թույլտվությունը ձեր հեռախոսում։"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Այս հավելվածը պահանջում է անվտանգության լրացուցիչ միջոցներ։ Օգտագործեք ձեր Android TV սարքը։"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Այս հավելվածը պահանջում է անվտանգության լրացուցիչ միջոցներ։ Օգտագործեք ձեր պլանշետը։"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Այս հավելվածը պահանջում է անվտանգության լրացուցիչ միջոցներ։ Օգտագործեք ձեր հեռախոսը։"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Հնարավոր չէ օգտագործել հեռախոսի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Հնարավոր չէ օգտագործել պլանշետի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Այս բովանդակությունը հասանելի չէ հեռարձակման ընթացքում։ Օգտագործեք ձեր հեռախոսը։"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Հեռարձակման ժամանակ հնարավոր չէ դիտել նկարը նկարի մեջ"</string>
<string name="system_locale_title" msgid="711882686834677268">"Կանխադրված"</string>
<string name="default_card_name" msgid="9198284935962911468">"ՔԱՐՏ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Ժամացույցները կառավարելու թույլտվություն ուղեկցող հավելվածի համար"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index c5e8ff9..818173c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"TOLAK"</string>
<string name="select_input_method" msgid="3971267998568587025">"Pilih metode masukan"</string>
<string name="show_ime" msgid="6406112007347443383">"Biarkan di layar meski keyboard fisik aktif"</string>
- <string name="hardware" msgid="1800597768237606953">"Tampilkan keyboard virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Gunakan keyboard virtual"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurasi <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurasi keyboard fisik"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Ketuk untuk memilih bahasa dan tata letak"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikasi tidak tersedia"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak tersedia saat ini."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> tidak tersedia"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Permintaan izin diblokir"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera tidak tersedia"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Lanjutkan di ponsel"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon tidak tersedia"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di perangkat Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplikasi ini tidak dapat diakses di <xliff:g id="DEVICE">%1$s</xliff:g> untuk saat ini. Coba di ponsel."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Aplikasi ini meminta izin tambahan, tetapi izin tidak dapat diberikan dalam sesi streaming. Berikan izin di perangkat Android TV terlebih dahulu."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Aplikasi ini meminta izin tambahan, tetapi izin tidak dapat diberikan dalam sesi streaming. Berikan izin di tablet terlebih dahulu."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Aplikasi ini meminta izin tambahan, tetapi izin tidak dapat diberikan dalam sesi streaming. Berikan izin di ponsel terlebih dahulu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Aplikasi ini meminta keamanan tambahan. Coba di perangkat Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Aplikasi ini meminta keamanan tambahan. Coba di tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Aplikasi ini meminta keamanan tambahan. Coba di ponsel."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera ponsel dari <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet dari <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Konten ini tidak dapat diakses saat melakukan streaming. Coba di ponsel."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tidak dapat menampilkan picture-in-picture saat streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"Default sistem"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTU <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Izin profil Smartwatch Pendamping untuk mengelola smartwatch"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 6784ceb..be42540 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"HAFNA"</string>
<string name="select_input_method" msgid="3971267998568587025">"Veldu innsláttaraðferð"</string>
<string name="show_ime" msgid="6406112007347443383">"Halda því á skjánum meðan vélbúnaðarlyklaborðið er virkt"</string>
- <string name="hardware" msgid="1800597768237606953">"Sýna sýndarlyklaborð"</string>
+ <string name="hardware" msgid="3611039921284836033">"Nota skjályklaborð"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Stilla <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Stilla vélbúnaðarlyklaborð"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Ýttu til að velja tungumál og útlit"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Forrit er ekki tiltækt"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ekki tiltækt núna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ekki í boði"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Heimildarbeiðni hafnað"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Myndavél ekki tiltæk"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Halda áfram í símanum"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Hljóðnemi ekki tiltækur"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í Android TV tækinu í staðinn."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í spjaldtölvunni í staðinn."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aðgangur að þessu í <xliff:g id="DEVICE">%1$s</xliff:g> er ekki í boði eins og er. Prófaðu það í símanum í staðinn."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Þetta forrit biður um viðbótarheimildir en ekki er hægt að veita heimildir í streymislotu. Veittu heimildina í Android TV-tækinu fyrst."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Þetta forrit biður um viðbótarheimildir en ekki er hægt að veita heimildir í streymislotu. Veittu heimildina í spjaldtölvunni fyrst."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Þetta forrit biður um viðbótarheimildir en ekki er hægt að veita heimildir í streymislotu. Veittu heimildina í símanum fyrst."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Þetta forrit biður um viðbótaröryggi. Prófaðu það í Android TV tækinu í staðinn."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Þetta forrit biður um viðbótaröryggi. Prófaðu það í spjaldtölvunni í staðinn."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Þetta forrit biður um viðbótaröryggi. Prófaðu það í símanum í staðinn."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ekki er hægt að opna myndavél símans úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ekki er hægt að opna myndavél spjaldtölvunnar úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Ekki er hægt að opna þetta á meðan streymi stendur yfir. Prófaðu það í símanum í staðinn."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ekki er hægt að horfa á mynd í mynd á meðan streymi er í gangi"</string>
<string name="system_locale_title" msgid="711882686834677268">"Sjálfgildi kerfis"</string>
<string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Fylgiforrit úrs – prófílheimild til að stjórna úrum"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0b420e0..5c12412 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RIFIUTO"</string>
<string name="select_input_method" msgid="3971267998568587025">"Scegli il metodo di immissione"</string>
<string name="show_ime" msgid="6406112007347443383">"Tieni sullo schermo quando è attiva la tastiera fisica"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostra tastiera virtuale"</string>
+ <string name="hardware" msgid="3611039921284836033">"Usa tastiera sullo schermo"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configura <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configura le tastiere fisiche"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tocca per selezionare la lingua e il layout"</string>
@@ -2317,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossibile accedere alla fotocamera del telefono dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossibile accedere alla fotocamera del tablet dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Impossibile accedere a questi contenuti durante lo streaming. Prova a usare il telefono."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossibile visualizzare Picture in picture durante lo streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"Predefinita di sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"SCHEDA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorizzazione per il profilo degli smartwatch complementari per gestire gli smartwatch"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 9644cb4..3dd65ad 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"עדיף שלא"</string>
<string name="select_input_method" msgid="3971267998568587025">"בחירה של שיטת הזנה"</string>
<string name="show_ime" msgid="6406112007347443383">"להשאיר במסך בזמן שהמקלדת הפיזית פעילה"</string>
- <string name="hardware" msgid="1800597768237606953">"הצגת מקלדת וירטואלית"</string>
+ <string name="hardware" msgid="3611039921284836033">"שימוש במקלדת שמופיעה במסך"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"הגדרה של <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"הגדרת מקלדות פיזיות"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"יש להקיש כדי לבחור שפה ופריסה"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"האפליקציה לא זמינה"</string>
<string name="app_blocked_message" msgid="542972921087873023">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא זמינה בשלב זה."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> לא זמינה"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"בקשת ההרשאה בוטלה"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"המצלמה לא זמינה"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"יש להמשיך בטלפון"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"המיקרופון לא זמין"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות במכשיר Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטאבלט."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, אפשר לנסות בטלפון."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"האפליקציה הזו מבקשת הרשאות נוספות, אך לא ניתן להעניק הרשאות בסשן סטרימינג. צריך לתת את ההרשאה קודם במכשיר Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"האפליקציה הזו מבקשת הרשאות נוספות, אך לא ניתן להעניק הרשאות בסשן סטרימינג. צריך לתת את ההרשאה קודם בטאבלט."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"האפליקציה הזו מבקשת הרשאות נוספות, אך לא ניתן להעניק הרשאות בסשן סטרימינג. צריך לתת את ההרשאה קודם בטלפון."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות במכשיר Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות בטאבלט."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות בטלפון."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"לא ניתן לגשת למצלמה של הטלפון מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"לא ניתן לגשת למצלמה של הטאבלט מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"אי אפשר לגשת לתוכן המאובטח הזה בזמן סטרימינג. במקום זאת, אפשר לנסות בטלפון."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"אי אפשר להציג תמונה בתוך תמונה בזמן סטרימינג"</string>
<string name="system_locale_title" msgid="711882686834677268">"ברירת המחדל של המערכת"</string>
<string name="default_card_name" msgid="9198284935962911468">"כרטיס <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"הרשאת פרופיל שעון לאפליקציה נלווית כדי לנהל שעונים"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index ea930a6..cc3c657 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"共有しない"</string>
<string name="select_input_method" msgid="3971267998568587025">"入力方法の選択"</string>
<string name="show_ime" msgid="6406112007347443383">"物理キーボードが有効になっていても画面に表示させます"</string>
- <string name="hardware" msgid="1800597768237606953">"仮想キーボードの表示"</string>
+ <string name="hardware" msgid="3611039921284836033">"画面キーボードの使用"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g>の設定"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"物理キーボードの設定"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"タップして言語とレイアウトを選択してください"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> からスマートフォンのカメラにアクセスできません"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> からタブレットのカメラにアクセスできません"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ストリーミング中はアクセスできません。スマートフォンでのアクセスをお試しください。"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ストリーミング中はピクチャー イン ピクチャーを表示できません"</string>
<string name="system_locale_title" msgid="711882686834677268">"システムのデフォルト"</string>
<string name="default_card_name" msgid="9198284935962911468">"カード <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ウォッチを管理できるコンパニオン ウォッチ プロファイル権限"</string>
@@ -2342,7 +2341,7 @@
<string name="keyboard_layout_notification_one_selected_message" msgid="4314216053129257197">"キーボードのレイアウトは<xliff:g id="LAYOUT_1">%s</xliff:g>に設定されています。タップで変更できます。"</string>
<string name="keyboard_layout_notification_two_selected_message" msgid="1876349944065922950">"キーボードのレイアウトは<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>に設定されています。タップで変更できます。"</string>
<string name="keyboard_layout_notification_three_selected_message" msgid="280734264593115419">"キーボードのレイアウトは<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>、<xliff:g id="LAYOUT_3">%3$s</xliff:g>に設定されています。タップで変更できます。"</string>
- <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"キーボードのレイアウトは<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>、<xliff:g id="LAYOUT_3">%3$s</xliff:g>に設定されています。タップで変更できます。"</string>
+ <string name="keyboard_layout_notification_more_than_three_selected_message" msgid="1581834181578206937">"キーボードのレイアウトは<xliff:g id="LAYOUT_1">%1$s</xliff:g>、<xliff:g id="LAYOUT_2">%2$s</xliff:g>、<xliff:g id="LAYOUT_3">%3$s</xliff:g>などに設定されています。タップで変更できます。"</string>
<string name="keyboard_layout_notification_multiple_selected_title" msgid="5242444914367024499">"物理キーボードの設定完了"</string>
<string name="keyboard_layout_notification_multiple_selected_message" msgid="6576533454124419202">"タップするとキーボードを表示できます"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 988adaf..4496376 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"უარყოფა"</string>
<string name="select_input_method" msgid="3971267998568587025">"აირჩიეთ შეყვანის მეთოდი"</string>
<string name="show_ime" msgid="6406112007347443383">"აქტიური ფიზიკური კლავიატურისას ეკრანზე შენარჩუნება"</string>
- <string name="hardware" msgid="1800597768237606953">"ვირტუალური კლავიატურის ჩვენება"</string>
+ <string name="hardware" msgid="3611039921284836033">"ეკრანული კლავიატურის გამოყენება"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"მოახდინეთ <xliff:g id="DEVICE_NAME">%s</xliff:g>-ის კონფიგურირება"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"მოახდინეთ ფიზიკური კლავიატურების კონფიგურირება"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"შეეხეთ ენისა და განლაგების ასარჩევად"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ტელეფონის კამერაზე წვდომა ვერ მოხერხდა თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ტაბლეტის კამერაზე წვდომა ვერ მოხერხდა თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"მასზე წვდომის მიᲦება შეუძლებელია სტრიმინგის დროს. ცადეთ ტელეფონიდან."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"სტრიმინგის დროს ეკრანის ეკრანში ნახვა შეუძლებელია"</string>
<string name="system_locale_title" msgid="711882686834677268">"სისტემის ნაგულისხმევი"</string>
<string name="default_card_name" msgid="9198284935962911468">"ბარათი <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"კომპანიონი საათის პროფილის ნებართვა საათების მართვაზე"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index aff1b3e..dd5d5fc 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -229,7 +229,7 @@
<string name="reboot_to_update_reboot" msgid="4474726009984452312">"Қайта іске қосылуда…"</string>
<string name="reboot_to_reset_title" msgid="2226229680017882787">"Зауыттық деректерді қалпына келтіру"</string>
<string name="reboot_to_reset_message" msgid="3347690497972074356">"Қайта іске қосылуда…"</string>
- <string name="shutdown_progress" msgid="5017145516412657345">"Өшірілуде…"</string>
+ <string name="shutdown_progress" msgid="5017145516412657345">"Өшіріліп жатыр…"</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Планшет өшіріледі."</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Android TV құрылғысы өшеді."</string>
<string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"Сағатыңыз өшіріледі."</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ҚАБЫЛДАМАУ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Енгізу әдісін таңдау"</string>
<string name="show_ime" msgid="6406112007347443383">"Физикалық пернетақта қосулы кезде оны экранға шығару"</string>
- <string name="hardware" msgid="1800597768237606953">"Виртуалдық пернетақтаны көрсету"</string>
+ <string name="hardware" msgid="3611039921284836033">"Экрандағы пернетақтаны пайдалану"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> конфигурациялау"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Физикалық пернетақталарды конфигурациялау"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Тіл мен пернетақта схемасын таңдау үшін түртіңіз."</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> қолжетімсіз"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Рұқсат сұрауы блокталды"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера қолжетімді емес"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Телефоннан жалғастыру"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон қолжетімді емес"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына Android TV құрылғысын пайдаланып көріңіз."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына планшетті пайдаланып көріңіз."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Қазір бұған <xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан кіру мүмкін емес. Оның орнына телефонды пайдаланып көріңіз."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Бұл қолданба қосымша рұқсаттар сұрап жатыр, бірақ трансляция жүріп жатқанда рұқсат беру мүмкін емес. Алдымен Android TV құрылғысында рұқсат беріңіз."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Бұл қолданба қосымша рұқсаттар сұрап жатыр, бірақ трансляция жүріп жатқанда рұқсат беру мүмкін емес. Алдымен планшетте рұқсат беріңіз."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Бұл қолданба қосымша рұқсаттар сұрап жатыр, бірақ трансляция жүріп жатқанда рұқсат беру мүмкін емес. Алдымен телефонда рұқсат беріңіз."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Бұл қолданба үшін қосымша қауіпсіздік шарасы қажет. Оның орнына Android TV құрылғысын пайдаланып көріңіз."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Бұл қолданба үшін қосымша қауіпсіздік шарасы қажет. Оның орнына планшетті пайдаланып көріңіз."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Бұл қолданба үшін қосымша қауіпсіздік шарасы қажет. Оның орнына телефонды пайдаланып көріңіз."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан телефон камерасын пайдалану мүмкін емес."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан планшет камерасын пайдалану мүмкін емес."</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Трансляция кезінде контентті көру мүмкін емес. Оның орнына телефоннан көріңіз."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Трансляция кезінде суреттегі суретті көру мүмкін емес."</string>
<string name="system_locale_title" msgid="711882686834677268">"Жүйенің әдепкі параметрі"</string>
<string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g>-КАРТА"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Сағаттарды басқаруға арналған қосымша сағат профилінің рұқсаты"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 46a7d8c..dc0260f 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1044,7 +1044,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ពង្រីកតំបន់ដោះសោ។"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"រុញដោះសោ។"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"លំនាំដោះសោ។"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"ដោះសោតាមទម្រង់មុខ។"</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"ការដោះសោដោយស្កេនមុខ។"</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"កូដ PIN ដោះសោ។"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ដោះកូដ Pin របស់សីុម។"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ដោះកូដ Puk របស់សីុម។"</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"បដិសេធ"</string>
<string name="select_input_method" msgid="3971267998568587025">"ជ្រើសវិធីសាស្ត្របញ្ចូល"</string>
<string name="show_ime" msgid="6406112007347443383">"ទុកវានៅលើអេក្រង់ខណៈពេលក្តារចុចពិតប្រាកដកំពុងសកម្ម"</string>
- <string name="hardware" msgid="1800597768237606953">"បង្ហាញក្ដារចុចនិម្មិត"</string>
+ <string name="hardware" msgid="3611039921284836033">"ប្រើក្ដារចុចលើអេក្រង់"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"កំណត់រចនាសម្ព័ន្ធ <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"កំណត់រចនាសម្ព័ន្ធក្ដារចុចរូបវន្ត"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ប៉ះដើម្បីជ្រើសភាសា និងប្លង់"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"មិនអាចចូលប្រើកាមេរ៉ាទូរសព្ទពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានទេ"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"មិនអាចចូលប្រើកាមេរ៉ាថេប្លេតពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានទេ"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"មិនអាចចូលប្រើប្រាស់ខ្លឹមសារនេះបានទេ ពេលផ្សាយ។ សូមសាកល្បងប្រើនៅលើទូរសព្ទរបស់អ្នកជំនួសវិញ។"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"មិនអាចមើលរូបក្នុងរូបខណៈពេលកំពុងផ្សាយបានទេ"</string>
<string name="system_locale_title" msgid="711882686834677268">"លំនាំដើមប្រព័ន្ធ"</string>
<string name="default_card_name" msgid="9198284935962911468">"កាត <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ការអនុញ្ញាតពីកម្រងព័ត៌មាននាឡិកាដៃគូ ដើម្បីគ្រប់គ្រងនាឡិកា"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 3773c1b..99e210c 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ನಿರಾಕರಿಸಿ"</string>
<string name="select_input_method" msgid="3971267998568587025">"ಇನ್ಪುಟ್ ವಿಧಾನವನ್ನು ಆರಿಸಿ"</string>
<string name="show_ime" msgid="6406112007347443383">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯವಾಗಿರುವಾಗ ಅದನ್ನು ಪರದೆಯ ಮೇಲಿರಿಸಿ"</string>
- <string name="hardware" msgid="1800597768237606953">"ವರ್ಚುವಲ್ ಕೀಬೋರ್ಡ್ ತೋರಿಸಿ"</string>
+ <string name="hardware" msgid="3611039921284836033">"ಆನ್-ಸ್ಕ್ರೀನ್ ಕೀಬೋರ್ಡ್ ಬಳಸಿ"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ಭೌತಿಕ ಕೀಬೋರ್ಡ್ಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ಭಾಷೆ ಮತ್ತು ವಿನ್ಯಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ಆ್ಯಪ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಇದೀಗ ಲಭ್ಯವಿಲ್ಲ."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ಲಭ್ಯವಿಲ್ಲ"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"ಅನುಮತಿ ವಿನಂತಿಯನ್ನು ನಿಗ್ರಹಿಸಲಾಗಿದೆ"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ಕ್ಯಾಮರಾ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ಫೋನ್ನಲ್ಲಿ ಮುಂದುವರಿಸಿ"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ಮೈಕ್ರೊಫೋನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ Android TV ಸಾಧನದಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ಈ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ನಲ್ಲಿ ಇದನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"ಈ ಆ್ಯಪ್ ಹೆಚ್ಚುವರಿ ಅನುಮತಿಗಳಿಗಾಗಿ ವಿನಂತಿಸುತ್ತಿದೆ, ಆದರೆ ಸ್ಟ್ರೀಮಿಂಗ್ ಸೆಶನ್ನಲ್ಲಿ ಅನುಮತಿಗಳನ್ನು ನೀಡಲಾಗುವುದಿಲ್ಲ. ಮೊದಲು ನಿಮ್ಮ Android TV ಸಾಧನದಲ್ಲಿ ಅನುಮತಿಯನ್ನು ನೀಡಿ."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"ಈ ಆ್ಯಪ್ ಹೆಚ್ಚುವರಿ ಅನುಮತಿಗಳಿಗಾಗಿ ವಿನಂತಿಸುತ್ತಿದೆ, ಆದರೆ ಸ್ಟ್ರೀಮಿಂಗ್ ಸೆಶನ್ನಲ್ಲಿ ಅನುಮತಿಗಳನ್ನು ನೀಡಲಾಗುವುದಿಲ್ಲ. ಮೊದಲು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಅನುಮತಿ ನೀಡಿ."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"ಈ ಆ್ಯಪ್ ಹೆಚ್ಚುವರಿ ಅನುಮತಿಗಳಿಗಾಗಿ ವಿನಂತಿಸುತ್ತಿದೆ, ಆದರೆ ಸ್ಟ್ರೀಮಿಂಗ್ ಸೆಶನ್ನಲ್ಲಿ ಅನುಮತಿಗಳನ್ನು ನೀಡಲಾಗುವುದಿಲ್ಲ. ಮೊದಲು ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಅನುಮತಿ ನೀಡಿ."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"ಈ ಆ್ಯಪ್ ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ. ಅದರ ಬದಲು ನಿಮ್ಮ Android TV ಸಾಧನದಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"ಈ ಆ್ಯಪ್ ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ. ಅದರ ಬದಲು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"ಈ ಆ್ಯಪ್ ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಯನ್ನು ವಿನಂತಿಸುತ್ತಿದೆ. ಅದರ ಬದಲು ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಮೂಲಕ ಫೋನ್ನ ಕ್ಯಾಮರಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಮೂಲಕ ಟ್ಯಾಬ್ಲೆಟ್ನ ಕ್ಯಾಮರಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ಸ್ಟ್ರೀಮ್ ಮಾಡುವಾಗ ಇದನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಫೋನ್ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ಸ್ಟ್ರೀಮ್ ಮಾಡುವಾಗ ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ವೀಕ್ಷಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="system_locale_title" msgid="711882686834677268">"ಸಿಸ್ಟಂ ಡೀಫಾಲ್ಟ್"</string>
<string name="default_card_name" msgid="9198284935962911468">"ಕಾರ್ಡ್ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ವಾಚ್ಗಳನ್ನು ನಿರ್ವಹಿಸುವುದಕ್ಕಾಗಿ ಕಂಪ್ಯಾನಿಯನ್ ವಾಚ್ ಪ್ರೊಫೈಲ್ ಅನುಮತಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d916ccf..97c28ad 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"거부"</string>
<string name="select_input_method" msgid="3971267998568587025">"입력 방법 선택"</string>
<string name="show_ime" msgid="6406112007347443383">"물리적 키보드가 활성 상태인 경우 화면에 켜 둠"</string>
- <string name="hardware" msgid="1800597768237606953">"가상 키보드 표시"</string>
+ <string name="hardware" msgid="3611039921284836033">"터치 키보드 사용"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> 설정"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"실제 키보드 설정"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"탭하여 언어와 레이아웃을 선택하세요."</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"앱을 사용할 수 없습니다"</string>
<string name="app_blocked_message" msgid="542972921087873023">"현재 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱을 사용할 수 없습니다."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> 사용할 수 없음"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"권한 요청 거부됨"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"카메라를 사용할 수 없음"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"휴대전화에서 진행하기"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"마이크를 사용할 수 없음"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 Android TV 기기에서 시도해 보세요."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 태블릿에서 시도해 보세요."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"현재 <xliff:g id="DEVICE">%1$s</xliff:g>에서 액세스할 수 없습니다. 대신 스마트폰에서 시도해 보세요."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"앱에서 추가 보안을 요청합니다. 그러나 스트리밍 세션에서는 권한을 부여할 수 없습니다. Android TV 기기에서 먼저 권한을 부여하세요."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"앱에서 추가 보안을 요청합니다. 그러나 스트리밍 세션에서는 권한을 부여할 수 없습니다. 태블릿에서 먼저 권한을 부여하세요."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"앱에서 추가 보안을 요청합니다. 그러나 스트리밍 세션에서는 권한을 부여할 수 없습니다. 휴대전화에서 먼저 권한을 부여하세요."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"앱에서 추가 보안을 요청합니다. 대신 Android TV 기기에서 시도해 보세요."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"앱에서 추가 보안을 요청합니다. 대신 태블릿에서 시도해 보세요."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"앱에서 추가 보안을 요청합니다. 대신 휴대전화에서 시도해 보세요."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 휴대전화 카메라에 액세스할 수 없습니다."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 태블릿 카메라에 액세스할 수 없습니다."</string>
<string name="vdm_secure_window" msgid="161700398158812314">"스트리밍 중에는 액세스할 수 없습니다. 대신 휴대전화에서 시도해 보세요."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"스트리밍 중에는 PIP 모드를 볼 수 없습니다."</string>
<string name="system_locale_title" msgid="711882686834677268">"시스템 기본값"</string>
<string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g> 카드"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"시계 관리를 위한 호환 시계 프로필 권한"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index b5c09bc..c250dc3 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1009,7 +1009,7 @@
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"Android TV түзмөгүңүздүн кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Android TV түзмөгүңүз эми демейки параметрлерге кайтарылат."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Сиз телефонду бөгөттөн чыгарууга <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Телефон баштапкы абалына келтирилет."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> секунддан кийин кайталаңыз."</string>
- <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Сүрөт үлгүсүн унутуп калдыңызбы?"</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Сүрөт үлгүсүн унутуп койдуңузбу?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Аккаунт менен кулпусун ачуу"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Өтө көп үлгү киргизүү аракети болду"</string>
<string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Бөгөттөн чыгарыш үчүн, Google эсебиңиз менен кириңиз."</string>
@@ -1017,7 +1017,7 @@
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Сырсөз"</string>
<string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Кирүү"</string>
<string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"Колдонуучу атыңыз же сырсөзүңүз туура эмес."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Колдонуучу атыңызды же сырсөзүңүздү унутуп калдыңызбы?\n"<b>"google.com/accounts/recovery"</b>" дарегине кайрылыңыз."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Колдонуучу атыңызды же сырсөзүңүздү унутуп койдуңузбу?\n"<b>"google.com/accounts/recovery"</b>" дарегине кайрылыңыз."</string>
<string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Текшерүүдө…"</string>
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"Кулпусун ачуу"</string>
<string name="lockscreen_sound_on_label" msgid="1660281470535492430">"Добушу күйүк"</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ЧЕТКЕ КАГУУ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Дайын киргизүү ыкмасын тандаңыз"</string>
<string name="show_ime" msgid="6406112007347443383">"Баскычтоп иштетилгенде экранда көрүнүп турат"</string>
- <string name="hardware" msgid="1800597768237606953">"Виртуалдык баскычтоп"</string>
+ <string name="hardware" msgid="3611039921284836033">"Экрандагы баскычтопту колдонуу"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> түзмөгүн конфигурациялоо"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Физикалык баскычтопторду конфигурациялоо"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Тил жана калып тандоо үчүн таптап коюңуз"</string>
@@ -1668,7 +1668,7 @@
<string name="kg_login_password_hint" msgid="3330530727273164402">"Сырсөз"</string>
<string name="kg_login_submit_button" msgid="893611277617096870">"Кирүү"</string>
<string name="kg_login_invalid_input" msgid="8292367491901220210">"Колдонуучу атыңыз же сырсөзүңүз туура эмес."</string>
- <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Колдонуучу атыңызды же сырсөзүңүздү унутуп калдыңызбы?\n"<b>"google.com/accounts/recovery"</b>" дарегине кайрылыңыз."</string>
+ <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Колдонуучу атыңызды же сырсөзүңүздү унутуп койдуңузбу?\n"<b>"google.com/accounts/recovery"</b>" дарегине кайрылыңыз."</string>
<string name="kg_login_checking_password" msgid="4676010303243317253">"Эсеп текшерилүүдө…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"Сиз PIN кодуңузду <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин кайталаңыз."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Сиз сырсөзүңүздү <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> секундадан кийин кайталаңыз."</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Колдонмо учурда жеткиликсиз"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> учурда жеткиликсиз"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> жеткиликсиз"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Уруксат берүү сурамы четке кагылды"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера жеткиликсиз"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Телефондон улантуу"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон жеткиликсиз"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Android TV түзмөгүңүздөн аракет кылып көрүңүз."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Планшетиңизден кирип көрүңүз."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Учурда буга <xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн кире албайсыз. Анын ордуна телефондон кирип көрүңүз."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Бул колдонмо кошумча уруксаттарды берүүнү суранып жатат, бирок алып ойнотуу сеансында уруксаттарды берүүгө болбойт. Адегенде Android TV түзмөгүндө уруксат бериңиз."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Бул колдонмо кошумча уруксаттарды берүүнү суранып жатат, бирок алып ойнотуу сеансында уруксаттарды берүүгө болбойт. Адегенде планшетте уруксат бериңиз."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Бул колдонмо кошумча уруксаттарды берүүнү суранып жатат, бирок алып ойнотуу сеансында уруксаттарды берүүгө болбойт. Адегенде телефондо уруксат бериңиз."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Бул колдонмо кошумча коопсуздукту иштетүүнү суранып жатат. Android TV түзмөгүңүздөн аракет кылып көрүңүз."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Бул колдонмо кошумча коопсуздукту иштетүүнү суранып жатат. Планшетиңизден кирип көрүңүз."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Бул колдонмо кошумча коопсуздукту иштетүүнү суранып жатат. Анын ордуна телефондон кирип көрүңүз."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн телефондун камерасына мүмкүнчүлүк жок"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн планшетиңиздин камерасына мүмкүнчүлүк жок"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Муну алып ойнотуу учурунда көрүүгө болбойт. Анын ордуна телефондон кирип көрүңүз."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Алып ойнотуп жатканда сүрөттөгү сүрөт көрүнбөйт"</string>
<string name="system_locale_title" msgid="711882686834677268">"Системанын демейки параметрлери"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Сааттын көмөкчү профилинин сааттарды тескөө уруксаты"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index bc3677c..bab1220 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ປະຕິເສດ"</string>
<string name="select_input_method" msgid="3971267998568587025">"ເລືອກຮູບແບບການປ້ອນ"</string>
<string name="show_ime" msgid="6406112007347443383">"ເປີດໃຊ້ໃຫ້ມັນຢູ່ໃນໜ້າຈໍໃນຂະນະທີ່ໃຊ້ແປ້ນພິມພາຍນອກຢູ່"</string>
- <string name="hardware" msgid="1800597768237606953">"ສະແດງແປ້ນພິມສະເໝືອນ"</string>
+ <string name="hardware" msgid="3611039921284836033">"ໃຊ້ແປ້ນພິມໃນໜ້າຈໍ"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"ຕັ້ງຄ່າ <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ຕັ້ງຄ່າແປ້ນພິມແທ້"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ແຕະເພື່ອເລືອກພາສາ ແລະ ໂຄງແປ້ນພິມ"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ແອັບບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"ບໍ່ສາມາດໃຊ້ <xliff:g id="ACTIVITY">%1$s</xliff:g> ໄດ້"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"ຄຳຮ້ອງຂໍການອະນຸຍາດຖືກລະງັບ"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ກ້ອງຖ່າຍຮູບບໍ່ສາມາດໃຊ້ໄດ້"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ສືບຕໍ່ຢູ່ໂທລະສັບ"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ໄມໂຄຣໂຟນບໍ່ສາມາດໃຊ້ໄດ້"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງໃຊ້ຢູ່ອຸປະກອນ Android TV ຂອງທ່ານແທນ."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງຢູ່ແທັບເລັດຂອງທ່ານແທນ."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ບໍ່ສາມາດເຂົ້າເຖິງແອັບນີ້ໄດ້ຢູ່ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໃນຕອນນີ້. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"ແອັບນີ້ກຳລັງຮ້ອງຂໍການອະນຸຍາດເພີ່ມເຕີມ, ແຕ່ບໍ່ສາມາດໃຫ້ການອະນຸຍາດໃນເຊດຊັນການສະຕຣີມໄດ້. ກະລຸນາໃຫ້ການອະນຸຍາດໃນອຸປະກອນ Android TV ຂອງທ່ານກ່ອນ."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"ແອັບນີ້ກຳລັງຮ້ອງຂໍການອະນຸຍາດເພີ່ມເຕີມ, ແຕ່ບໍ່ສາມາດໃຫ້ການອະນຸຍາດໃນເຊດຊັນການສະຕຣີມໄດ້. ກະລຸນາໃຫ້ການອະນຸຍາດໃນແທັບເລັດຂອງທ່ານກ່ອນ."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"ແອັບນີ້ກຳລັງຮ້ອງຂໍການອະນຸຍາດເພີ່ມເຕີມ, ແຕ່ບໍ່ສາມາດໃຫ້ການອະນຸຍາດໃນເຊດຊັນການສະຕຣີມໄດ້. ກະລຸນາໃຫ້ການອະນຸຍາດໃນໂທລະສັບຂອງທ່ານກ່ອນ."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"ແອັບນີ້ກຳລັງຮ້ອງຂໍຄວາມປອດໄພເພີ່ມເຕີມ. ກະລຸນາລອງໃຊ້ຢູ່ອຸປະກອນ Android TV ຂອງທ່ານແທນ."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"ແອັບນີ້ກຳລັງຮ້ອງຂໍຄວາມປອດໄພເພີ່ມເຕີມ. ກະລຸນາລອງຢູ່ແທັບເລັດຂອງທ່ານແທນ."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"ແອັບນີ້ກຳລັງຮ້ອງຂໍຄວາມປອດໄພເພີ່ມເຕີມ. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງໂທລະສັບຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງແທັບເລັດຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ບໍ່ສາມາດເຂົ້າເຖິງເນື້ອຫານີ້ໄດ້ໃນຂະນະທີ່ຍັງສະຕຣີມຢູ່. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ບໍ່ສາມາດເບິ່ງການສະແດງຜົນຊ້ອນກັນໃນຂະນະທີ່ສະຕຣີມໄດ້"</string>
<string name="system_locale_title" msgid="711882686834677268">"ຄ່າເລີ່ມຕົ້ນຂອງລະບົບ"</string>
<string name="default_card_name" msgid="9198284935962911468">"ບັດ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ສິດການອະນຸຍາດສຳລັບໂປຣໄຟລ໌ໃນໂມງຊ່ວຍເຫຼືອເພື່ອຈັດການໂມງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 1d88adc..10b625e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ATMESTI"</string>
<string name="select_input_method" msgid="3971267998568587025">"Pasirinkite įvesties metodą"</string>
<string name="show_ime" msgid="6406112007347443383">"Palikti ekrane, kol fizinė klaviatūra aktyvi"</string>
- <string name="hardware" msgid="1800597768237606953">"Rodyti virtualiąją klaviatūrą"</string>
+ <string name="hardware" msgid="3611039921284836033">"Ekrano klaviatūros naudojimas"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"„<xliff:g id="DEVICE_NAME">%s</xliff:g>“ konfigūravimas"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Fizinių klaviatūrų konfigūravimas"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Palieskite, kad pasirinktumėte kalbą ir išdėstymą"</string>
@@ -1961,8 +1961,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Programa nepasiekiama."</string>
<string name="app_blocked_message" msgid="542972921087873023">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ šiuo metu nepasiekiama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"„<xliff:g id="ACTIVITY">%1$s</xliff:g>“ nepasiekiama"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Leidimo užklausa atmesta"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nepasiekiama"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Tęsti telefone"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonas nepasiekiamas"</string>
@@ -1973,12 +1972,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti „Android TV“ įrenginį."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti planšetinį kompiuterį."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Šįkart nepavyksta pasiekti programos iš jūsų „<xliff:g id="DEVICE">%1$s</xliff:g>“. Pabandykite naudoti telefoną."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Ši programa prašo papildomų leidimų, bet jų negalima suteikti per srautinio perdavimo seansą. Leidimą pirmiausia suteikite „Android TV“ įrenginyje."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Ši programa prašo papildomų leidimų, bet jų negalima suteikti per srautinio perdavimo seansą. Leidimą pirmiausia suteikite planšetiniame kompiuteryje."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Ši programa prašo papildomų leidimų, bet jų negalima suteikti per srautinio perdavimo seansą. Leidimą pirmiausia suteikite telefone."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ši programa prašo papildomų saugos funkcijų. Pabandykite naudoti „Android TV“ įrenginį."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ši programa prašo papildomų saugos funkcijų. Pabandykite naudoti planšetinį kompiuterį."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ši programa prašo papildomų saugos funkcijų. Pabandykite naudoti telefoną."</string>
@@ -2322,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nepavyko pasiekti telefono fotoaparato iš „<xliff:g id="DEVICE">%1$s</xliff:g>“"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nepavyko pasiekti planšetinio kompiuterio fotoaparato iš „<xliff:g id="DEVICE">%1$s</xliff:g>“"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Nepavyksta pasiekti perduodant srautu. Pabandykite naudoti telefoną."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Negalima peržiūrėti vaizdo vaizde perduodant srautu"</string>
<string name="system_locale_title" msgid="711882686834677268">"Numatytoji sistemos vertė"</string>
<string name="default_card_name" msgid="9198284935962911468">"KORTELĖ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Papildomos programos laikrodžio profilio leidimas valdyti laikrodžius"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 9c467c4..3076b56 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"NORAIDĪT"</string>
<string name="select_input_method" msgid="3971267998568587025">"Ievades metodes izvēle"</string>
<string name="show_ime" msgid="6406112007347443383">"Paturēt ekrānā, kamēr ir aktīva fiziskā tastatūra"</string>
- <string name="hardware" msgid="1800597768237606953">"Virtuālās tastatūras rādīšana"</string>
+ <string name="hardware" msgid="3611039921284836033">"Izmantojiet ekrāna tastatūru"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Jākonfigurē <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurējiet fiziskās tastatūras"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Pieskarieties, lai atlasītu valodu un izkārtojumu"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Lietotne nav pieejama"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> pašlaik nav pieejama."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nav pieejams"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Atļaujas pieprasījums bloķēts"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nav pieejama"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Turpiniet tālrunī"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofons nav pieejams"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā Android TV ierīcē."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā planšetdatorā."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Šajā ierīcē (<xliff:g id="DEVICE">%1$s</xliff:g>) pašlaik nevar piekļūt šai lietotnei. Mēģiniet tai piekļūt savā tālrunī."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Šī lietotne pieprasa papildu atļaujas, taču atļaujas nevar piešķirt straumēšanas sesijā. Vispirms piešķiriet attiecīgo atļauju savā Android TV ierīcē."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Šī lietotne pieprasa papildu atļaujas, taču atļaujas nevar piešķirt straumēšanas sesijā. Vispirms piešķiriet attiecīgo atļauju savā planšetdatorā."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Šī lietotne pieprasa papildu atļaujas, taču atļaujas nevar piešķirt straumēšanas sesijā. Vispirms piešķiriet attiecīgo atļauju savā tālrunī."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Šī lietotne pieprasa papildu drošību. Mēģiniet tai piekļūt savā Android TV ierīcē."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Šī lietotne pieprasa papildu drošību. Mēģiniet tai piekļūt savā planšetdatorā."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Šī lietotne pieprasa papildu drošību. Mēģiniet tai piekļūt savā tālrunī."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nevar piekļūt tālruņa kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nevar piekļūt planšetdatora kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Straumēšanas laikā nevar piekļūt šim saturam. Mēģiniet tam piekļūt savā tālrunī."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Straumēšanas laikā nevar skatīt attēlu attēlā"</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistēmas noklusējums"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Palīglietotnes pulksteņa profila atļauja pārvaldīt pulksteņus"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index d7847d6..8622bdc 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1259,7 +1259,7 @@
<string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Се стартуваат апликациите."</string>
<string name="android_upgrading_complete" msgid="409800058018374746">"Подигањето завршува."</string>
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Го притиснавте копчето за вклучување — така обично се исклучува екранот.\n\nДопрете лесно додека го поставувате отпечатокот."</string>
- <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"За да завршите со поставувањето, исклучете го екранот"</string>
+ <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"За излез, исклучете го екранот"</string>
<string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Исклучи"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"Да продолжи потврдувањето на отпечаток?"</string>
<string name="fp_power_button_bp_message" msgid="2983163038168903393">"Го притиснавте копчето за вклучување — така обично се исклучува екранот.\n\nДопрете лесно за да го потврдите отпечатокот."</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ОДБИЈ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Одбери метод на внес"</string>
<string name="show_ime" msgid="6406112007347443383">"Прикажувај ја на екранот додека е активна физичката тастатура"</string>
- <string name="hardware" msgid="1800597768237606953">"Прикажи виртуелна тастатура"</string>
+ <string name="hardware" msgid="3611039921284836033">"Користете тастатура на екран"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Конфигурирање на <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Конфигурирање физички тастатури"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Допрете за избирање јазик и распоред"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Апликацијата не е достапна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> не е достапна во моментов."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> е недостапна"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Барањето за дозвола е потиснато"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камерата е недостапна"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продолжете на телефонот"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофонот не е достапен"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот Android TV како алтернатива."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот таблет како алтернатива."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ова не може да се отвори на <xliff:g id="DEVICE">%1$s</xliff:g> во моментов. Пробајте на вашиот телефон како алтернатива."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Апликацијава бара дополнителни дозволи, но нив не може да ги доделите во сесија за стриминг. Прво доделете ја дозволата на вашиот уред со Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Апликацијава бара дополнителни дозволи, но нив не може да ги доделите во сесија за стриминг. Прво доделете ја дозволата на вашиот таблет."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Апликацијава бара дополнителни дозволи, но нив не може да ги доделите во сесија за стриминг. Прво доделете ја дозволата на вашиот телефон."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Апликацијава бара дополнителна безбедност. Пробајте на вашиот Android TV како алтернатива."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Апликацијава бара дополнителна безбедност. Пробајте на вашиот таблет како алтернатива."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Апликацијава бара дополнителна безбедност. Пробајте на вашиот телефон како алтернатива."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се пристапи до камерата на вашиот телефон од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се пристапи до камерата на вашиот таблет од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"До ова не може да се пристапи при стриминг. Наместо тоа, пробајте на вашиот телефон."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Не може да се прикажува слика во слика при стримување"</string>
<string name="system_locale_title" msgid="711882686834677268">"Стандарден за системот"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТИЧКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дозвола за профилот на придружен часовник за управување со часовници"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 9db30b0..c17ff94 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"നിരസിക്കുക"</string>
<string name="select_input_method" msgid="3971267998568587025">"ഇൻപുട്ട് രീതി തിരഞ്ഞെടുക്കുക"</string>
<string name="show_ime" msgid="6406112007347443383">"ഫിസിക്കൽ കീബോർഡ് സജീവമായിരിക്കുമ്പോൾ സ്ക്രീനിൽ നിലനിർത്തുക"</string>
- <string name="hardware" msgid="1800597768237606953">"വെർച്വൽ കീബോർഡ് കാണിക്കുക"</string>
+ <string name="hardware" msgid="3611039921284836033">"ഓൺ-സ്ക്രീൻ കീബോർഡ് ഉപയോഗിക്കൂ"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> കോൺഫിഗർ ചെയ്യുക"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"യഥാർത്ഥ കീബോർഡുകൾ കോൺഫിഗർ ചെയ്യുക"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ഭാഷയും ലേഔട്ടും തിരഞ്ഞെടുക്കുന്നതിന് ടാപ്പ് ചെയ്യുക"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> എന്നതിൽ നിന്ന് ഫോണിന്റെ ക്യാമറ ആക്സസ് ചെയ്യാനാകില്ല"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> എന്നതിൽ നിന്ന് ടാബ്ലെറ്റിന്റെ ക്യാമറ ആക്സസ് ചെയ്യാനാകില്ല"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"സ്ട്രീം ചെയ്യുമ്പോൾ ഇത് ആക്സസ് ചെയ്യാനാകില്ല. പകരം നിങ്ങളുടെ ഫോണിൽ ശ്രമിച്ച് നോക്കൂ."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"സ്ട്രീമിംഗിനിടെ ചിത്രത്തിനുള്ളിൽ ചിത്രം കാണാനാകില്ല"</string>
<string name="system_locale_title" msgid="711882686834677268">"സിസ്റ്റം ഡിഫോൾട്ട്"</string>
<string name="default_card_name" msgid="9198284935962911468">"കാർഡ് <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"വാച്ചുകൾ മാനേജ് ചെയ്യുന്നതിന് സഹകാരി ആപ്പിനുള്ള വാച്ച് പ്രൊഫൈൽ അനുമതി"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 2476e1e..71be64e 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ТАТГАЛЗАХ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Оруулах аргыг сонгоно уу"</string>
<string name="show_ime" msgid="6406112007347443383">"Биет гар идэвхтэй үед үүнийг дэлгэцэд харуулна уу"</string>
- <string name="hardware" msgid="1800597768237606953">"Хийсвэр гарыг харуулах"</string>
+ <string name="hardware" msgid="3611039921284836033">"Дэлгэц дээрх гарыг ашиглах"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g>-г тохируулна уу"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Биет гарыг тохируулна уу"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Хэл болон бүдүүвчийг сонгохын тулд дарна уу"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Апп боломжгүй байна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> яг одоо боломжгүй байна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> боломжгүй байна"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Зөвшөөрлийн хүсэлтийг зогсоосон"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камер боломжгүй байна"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Утсан дээр үргэлжлүүлэх"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон боломжгүй байна"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь Android TV төхөөрөмж дээрээ туршиж үзнэ үү."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь таблет дээрээ туршиж үзнэ үү."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Одоогоор үүнд таны <xliff:g id="DEVICE">%1$s</xliff:g> дээрээс хандах боломжгүй. Оронд нь утсан дээрээ туршиж үзнэ үү."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Энэ апп нэмэлт зөвшөөрөл хүсэж байгаа ч дамжуулалтын харилцан үйлдлийн үеэр зөвшөөрөл олгох боломжгүй. Эхлээд Android TV төхөөрөмждөө зөвшөөрөл олгоно уу."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Энэ апп нэмэлт зөвшөөрөл хүсэж байгаа ч дамжуулалтын харилцан үйлдлийн үеэр зөвшөөрөл олгох боломжгүй. Эхлээд таблетдаа зөвшөөрөл олгоно уу."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Энэ апп нэмэлт зөвшөөрөл хүсэж байгаа ч дамжуулалтын харилцан үйлдлийн үеэр зөвшөөрөл олгох боломжгүй. Эхлээд утсандаа зөвшөөрөл олгоно уу."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Энэ апп нэмэлт аюулгүй байдал хүсэж байна. Оронд нь Android TV төхөөрөмж дээрээ туршиж үзнэ үү."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Энэ апп нэмэлт аюулгүй байдал хүсэж байна. Оронд нь таблет дээрээ туршиж үзнэ үү."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Энэ апп нэмэлт аюулгүй байдал хүсэж байна. Оронд нь утсан дээрээ туршиж үзнэ үү."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Таны <xliff:g id="DEVICE">%1$s</xliff:g>-с утасны камерт хандах боломжгүй"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Таны <xliff:g id="DEVICE">%1$s</xliff:g>-с таблетын камерт хандах боломжгүй"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Стримингийн үед үүнд хандах боломжгүй. Оронд нь утас дээрээ туршиж үзнэ үү."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Дамжуулах явцад дэлгэц доторх дэлгэцийг үзэх боломжгүй"</string>
<string name="system_locale_title" msgid="711882686834677268">"Системийн өгөгдмөл"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дэмжигч цагны профайлын цаг удирдах зөвшөөрөл"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 484af02..b04244a 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"नकार द्या"</string>
<string name="select_input_method" msgid="3971267998568587025">"इनपुट पद्धत निवडा"</string>
<string name="show_ime" msgid="6406112007347443383">"भौतिक कीबोर्ड सक्रिय असताना त्यास स्क्रीनवर ठेवा"</string>
- <string name="hardware" msgid="1800597768237606953">"व्हर्च्युअल कीबोर्ड दर्शवा"</string>
+ <string name="hardware" msgid="3611039921284836033">"ऑन-स्क्रीन कीबोर्ड वापरा"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> कॉंफिगर करा"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"वास्तविक कीबोर्ड कॉंफिगर करा"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"भाषा आणि लेआउट निवडण्यासाठी टॅप करा"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वरून फोनचा कॅमेरा अॅक्सेस करू शकत नाही"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वरून टॅबलेटचा कॅमेरा अॅक्सेस करू शकत नाही"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रीम करताना हे अॅक्सेस केले जाऊ शकत नाही. त्याऐवजी तुमच्या फोनवर अॅक्सेस करून पहा."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रीम होत असताना चित्रात-चित्र पाहू शकत नाही"</string>
<string name="system_locale_title" msgid="711882686834677268">"सिस्टीम डीफॉल्ट"</string>
<string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"वॉच व्यवस्थापित करण्यासाठी सहयोगी वॉच प्रोफाइलची परवानगी"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index af01461..eccb2ae 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"TOLAK"</string>
<string name="select_input_method" msgid="3971267998568587025">"Pilih kaedah input"</string>
<string name="show_ime" msgid="6406112007347443383">"Pastikannya pada skrin, semasa papan kekunci fizikal aktif"</string>
- <string name="hardware" msgid="1800597768237606953">"Tunjukkan papan kekunci maya"</string>
+ <string name="hardware" msgid="3611039921284836033">"Guna papan kekunci pada skrin"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurasikan <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurasikan papan kekunci fizikal"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Ketik untuk memilih bahasa dan reka letak"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera telefon daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Kandungan ini tidak boleh diakses semasa penstriman. Cuba pada telefon anda."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tidak dapat melihat gambar dalam gambar semasa penstriman"</string>
<string name="system_locale_title" msgid="711882686834677268">"Lalai sistem"</string>
<string name="default_card_name" msgid="9198284935962911468">"KAD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kebenaran profil Jam Tangan rakan untuk mengurus jam tangan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index d5ba8b6..4a8cafc 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -229,7 +229,7 @@
<string name="reboot_to_update_reboot" msgid="4474726009984452312">"ပြန်လည်စတင်နေ…"</string>
<string name="reboot_to_reset_title" msgid="2226229680017882787">"စက်ရုံထုတ်အခြေအနေပြန်ယူခြင်း"</string>
<string name="reboot_to_reset_message" msgid="3347690497972074356">"ပြန်လည်စတင်နေ…"</string>
- <string name="shutdown_progress" msgid="5017145516412657345">"စက်ပိတ်ပါမည်"</string>
+ <string name="shutdown_progress" msgid="5017145516412657345">"စက်ပိတ်နေသည်…"</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"သင့်တက်ဘလက်အား စက်ပိတ်ပါမည်"</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"သင့် Android TV စက်ပစ္စည်း ပိတ်သွားပါမည်။"</string>
<string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"သင်၏ ကြည့်ရှုမှု ပိတ်ပစ်မည်။"</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ငြင်းပယ်ပါ"</string>
<string name="select_input_method" msgid="3971267998568587025">"ထည့်သွင်းရေး နည်းကို ရွေးရန်"</string>
<string name="show_ime" msgid="6406112007347443383">"စက်၏ကီးဘုတ် ဖွင့်ထားစဉ်တွင် ၎င်းကို ဖန်သားပြင်ပေါ်တွင် ဆက်ထားပါ"</string>
- <string name="hardware" msgid="1800597768237606953">"ပကတိအသွင်ကီးဘုတ်ပြရန်"</string>
+ <string name="hardware" msgid="3611039921284836033">"မျက်နှာပြင် လက်ကွက် သုံးခြင်း"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ကို စီစဉ်သတ်မှတ်ရန်"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ပကတိကီးဘုတ်များကို စီစဉ်သတ်မှတ်ရန်"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ဘာသာစကားနှင့် အသွင်အပြင်ရွေးချယ်ရန် တို့ပါ"</string>
@@ -1954,13 +1954,12 @@
<string name="app_suspended_more_details" msgid="211260942831587014">"ပိုမိုလေ့လာရန်"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"အက်ပ်ကို ခဏမရပ်တော့ရန်"</string>
<string name="work_mode_off_title" msgid="6367463960165135829">"အလုပ်သုံးအက်ပ် ပြန်ဖွင့်မလား။"</string>
- <string name="work_mode_turn_on" msgid="5316648862401307800">"ပြန်စရန်"</string>
+ <string name="work_mode_turn_on" msgid="5316648862401307800">"ပြန်ဖွင့်ရန်"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"အရေးပေါ်"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"အက်ပ်ကို မရနိုင်ပါ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ယခု မရနိုင်ပါ။"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> မရနိုင်ပါ"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"ခွင့်ပြုချက်တောင်းဆိုမှု ပိတ်ထားသည်"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ကင်မရာ မရနိုင်ပါ"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ဖုန်းပေါ်တွင် ရှေ့ဆက်ပါ"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"မိုက်ခရိုဖုန်း မရနိုင်ပါ"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား Android TV စက်တွင် စမ်းကြည့်ပါ။"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား တက်ဘလက်တွင် စမ်းကြည့်ပါ။"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"၎င်းအား ယခု သင့် <xliff:g id="DEVICE">%1$s</xliff:g> တွင် ဝင်၍မရပါ။ ယင်းအစား ဖုန်းတွင် စမ်းကြည့်ပါ။"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"ဤအက်ပ်သည် နောက်ထပ်ခွင့်ပြုချက်များကို တောင်းဆိုနေသော်လည်း တိုက်ရိုက်လွှင့်စက်ရှင်တွင် ခွင့်ပြုချက်များ ပေး၍မရပါ။ သင့် Android TV စက်တွင် ဦးစွာ ခွင့်ပြုချက်ပေးပါ။"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"ဤအက်ပ်သည် နောက်ထပ်ခွင့်ပြုချက်များကို တောင်းဆိုနေသော်လည်း တိုက်ရိုက်လွှင့်စက်ရှင်တွင် ခွင့်ပြုချက်များ ပေး၍မရပါ။ သင့်တက်ဘလက်တွင် ဦးစွာ ခွင့်ပြုချက်ပေးပါ။"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"ဤအက်ပ်သည် နောက်ထပ်ခွင့်ပြုချက်များကို တောင်းဆိုနေသော်လည်း တိုက်ရိုက်လွှင့်စက်ရှင်တွင် ခွင့်ပြုချက်များ ပေး၍မရပါ။ သင့်ဖုန်းတွင် ဦးစွာ ခွင့်ပြုချက်ပေးပါ။"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"ဤအက်ပ်က ထပ်ဆောင်းလုံခြုံရေးကို တောင်းဆိုနေသည်။ Android TV စက်တွင် စမ်းကြည့်ပါ။"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"ဤအက်ပ်က ထပ်ဆောင်းလုံခြုံရေးကို တောင်းဆိုနေသည်။ တက်ဘလက်တွင် စမ်းကြည့်ပါ။"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"ဤအက်ပ်က ထပ်ဆောင်းလုံခြုံရေးကို တောင်းဆိုနေသည်။ ဖုန်းတွင် စမ်းကြည့်ပါ။"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"သင်၏ <xliff:g id="DEVICE">%1$s</xliff:g> မှ ဖုန်းကင်မရာကို သုံး၍မရပါ"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"သင်၏ <xliff:g id="DEVICE">%1$s</xliff:g> မှ တက်ဘလက်ကင်မရာကို သုံး၍မရပါ"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"တိုက်ရိုက်လွှင့်နေစဉ် ၎င်းကို မသုံးနိုင်ပါ။ ၎င်းအစား ဖုန်းတွင် စမ်းကြည့်ပါ။"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"တိုက်ရိုက်လွှင့်စဉ် နှစ်ခုထပ်၍ မကြည့်နိုင်ပါ"</string>
<string name="system_locale_title" msgid="711882686834677268">"စနစ်မူရင်း"</string>
<string name="default_card_name" msgid="9198284935962911468">"ကတ် <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"လက်ပတ်နာရီများစီမံရန် ‘တွဲဖက်နာရီ’ ပရိုဖိုင်ခွင့်ပြုချက်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f2f14b8..a999815 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"AVSLÅ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Velg inndatametode"</string>
<string name="show_ime" msgid="6406112007347443383">"Ha den på skjermen mens det fysiske tastaturet er aktivt"</string>
- <string name="hardware" msgid="1800597768237606953">"Vis det virtuelle tastaturet"</string>
+ <string name="hardware" msgid="3611039921284836033">"Bruk skjermtastaturet"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurer <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurer de fysiske tastaturene"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Trykk for å velge språk og layout"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Appen er ikke tilgjengelig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> er ikke tilgjengelig for øyeblikket."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> er utilgjengelig"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Forespørselen om tillatelse er skjult"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kameraet er utilgjengelig"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Fortsett på telefonen"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonen er utilgjengelig"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på Android TV-enheten din i stedet."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på nettbrettet ditt i stedet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Dette er ikke tilgjengelig på <xliff:g id="DEVICE">%1$s</xliff:g> for øyeblikket. Prøv på telefonen din i stedet."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Denne appen ber om flere tillatelser, men du kan ikke gi tillatelser i en strømmeøkt. Gi tillatelsen på Android TV-enheten først."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Denne appen ber om flere tillatelser, men du kan ikke gi tillatelser i en strømmeøkt. Gi tillatelsen på nettbrettet først."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Denne appen ber om flere tillatelser, men du kan ikke gi tillatelser i en strømmeøkt. Gi tillatelsen på telefonen først."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Denne appen ber om ekstra sikkerhet. Prøv på Android TV-enheten din i stedet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Denne appen ber om ekstra sikkerhet. Prøv på nettbrettet ditt i stedet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Denne appen ber om ekstra sikkerhet. Prøv på telefonen din i stedet."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Det er ikke mulig å få tilgang til telefonkameraet fra <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Det er ikke mulig å få tilgang til kameraet på nettbrettet fra <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Dette er ikke tilgjengelig under strømming. Prøv på telefonen i stedet."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan ikke se bilde-i-bilde under strømming"</string>
<string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string>
<string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Klokkeprofil-tillatelse for følgeapp for å administrere klokker"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 9023889..c448f01 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"अस्वीकार गर्नुहोस्"</string>
<string name="select_input_method" msgid="3971267998568587025">"निवेश विधि छान्नुहोस्"</string>
<string name="show_ime" msgid="6406112007347443383">"फिजिकल किबोर्ड सक्रिय हुँदा यसलाई स्क्रिनमा राखियोस्"</string>
- <string name="hardware" msgid="1800597768237606953">"भर्चुअल किबोर्ड देखाउनुहोस्"</string>
+ <string name="hardware" msgid="3611039921284836033">"अनस्क्रिन किबोर्ड प्रयोग गर्नुहोस्"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> कन्फिगर गर्नुहोस्"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"भौतिक किबोर्डहरू कन्फिगर गर्नुहोस्"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"एप उपलब्ध छैन"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> अहिले उपलब्ध छैन।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> उपलब्ध छैन"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"अनुमतिसम्बन्धी अनुरोध रद्द गरिएको छ"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"क्यामेरा उपलब्ध छैन"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"फोनमा जारी राख्नुहोस्"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"माइक्रोफोन उपलब्ध छैन"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको Android TV डिभाइसमा स्ट्रिम गरी हेर्नुहोस्।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको ट्याब्लेटमा स्ट्रिम गरी हेर्नुहोस्।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"यस बखत तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मा यो एप स्ट्रिम गर्न मिल्दैन। बरु तपाईंको फोनमा स्ट्रिम गरी हेर्नुहोस्।"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"यो एपले अतिरिक्त अनुमति मागिरहेको छ तर स्ट्रिमिङ सत्रमा अनुमति दिन मिल्दैन। सर्वप्रथम आफ्नो Android TV डिभाइसमा अनुमति दिनुहोस्।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"यो एपले अतिरिक्त अनुमति मागिरहेको छ तर स्ट्रिमिङ सत्रमा अनुमति दिन मिल्दैन। सर्वप्रथम आफ्नो ट्याब्लेटमा अनुमति दिनुहोस्।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"यो एपले अतिरिक्त अनुमति मागिरहेको छ तर स्ट्रिमिङ सत्रमा अनुमति दिन मिल्दैन। सर्वप्रथम आफ्नो फोनमा अनुमति दिनुहोस्।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"यो एपले सुरक्षासम्बन्धी अतिरिक्त सुविधा अन गर्न अनुरोध गरिरहेको छ। बरु तपाईंको Android TV डिभाइसमा स्ट्रिम गरी हेर्नुहोस्।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"यो एपले सुरक्षासम्बन्धी अतिरिक्त सुविधा अन गर्न अनुरोध गरिरहेको छ। बरु तपाईंको ट्याब्लेटमा स्ट्रिम गरी हेर्नुहोस्।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"यो एपले सुरक्षासम्बन्धी अतिरिक्त सुविधा अन गर्न अनुरोध गरिरहेको छ। बरु तपाईंको फोनमा स्ट्रिम गरी हेर्नुहोस्।"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मार्फत फोनको क्यामेरा प्रयोग गर्न मिल्दैन"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मार्फत ट्याब्लेटको क्यामेरा प्रयोग गर्न मिल्दैन"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रिम गरिरहेका बेला यो सामग्री हेर्न तथा प्रयोग गर्न मिल्दैन। बरु आफ्नो फोनमार्फत सो सामग्री हेर्ने तथा प्रयोग गर्ने प्रयास गर्नुहोस्।"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रिम गरिरहेका बेला picture-in-picture मोड प्रयोग गर्न मिल्दैन"</string>
<string name="system_locale_title" msgid="711882686834677268">"सिस्टम डिफल्ट"</string>
<string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"स्मार्टवाचहरू व्यवस्थापन गर्ने सहयोगी वाच प्रोफाइलसम्बन्धी अनुमति"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ef7ea51..5726d7f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"WEIGEREN"</string>
<string name="select_input_method" msgid="3971267998568587025">"Invoermethode selecteren"</string>
<string name="show_ime" msgid="6406112007347443383">"Toon op het scherm terwijl het fysieke toetsenbord actief is"</string>
- <string name="hardware" msgid="1800597768237606953">"Virtueel toetsenbord tonen"</string>
+ <string name="hardware" msgid="3611039921284836033">"Schermtoetsenbord gebruiken"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> instellen"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Fysieke toetsenborden instellen"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tik om een taal en indeling te selecteren"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"App is niet beschikbaar"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> is momenteel niet beschikbaar."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> niet beschikbaar"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Verzoek om rechten onderdrukt"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Camera niet beschikbaar"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Doorgaan op telefoon"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microfoon niet beschikbaar"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je Android TV-apparaat."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Je hebt hier nu geen toegang toe op je <xliff:g id="DEVICE">%1$s</xliff:g>. Probeer het in plaats daarvan op je telefoon."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Deze app vraagt om extra rechten, maar je kunt geen rechten verlenen tijdens een streamingsessie. Verleen het recht eerst op je Android TV-apparaat."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Deze app vraagt om extra rechten, maar je kunt geen rechten verlenen tijdens een streamingsessie. Verleen het recht eerst op je tablet."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Deze app vraagt om extra rechten, maar je kunt geen rechten verlenen tijdens een streamingsessie. Verleen het recht eerst op je telefoon."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Deze app vraagt om aanvullende beveiliging. Probeer het in plaats daarvan op je Android TV-apparaat."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Deze app vraagt om aanvullende beveiliging. Probeer het in plaats daarvan op je tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Deze app vraagt om aanvullende beveiliging. Probeer het in plaats daarvan op je telefoon."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kan geen toegang tot de camera van de telefoon krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kan geen toegang tot de camera van de tablet krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Je hebt hier geen toegang toe tijdens streaming. Probeer het in plaats daarvan op je telefoon."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan scherm-in-scherm niet bekijken tijdens het streamen"</string>
<string name="system_locale_title" msgid="711882686834677268">"Systeemstandaard"</string>
<string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Smartwatchprofiel voor bijbehorende app om smartwatches te beheren"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 77f7bae..4f5f79d 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -229,7 +229,7 @@
<string name="reboot_to_update_reboot" msgid="4474726009984452312">"ରିଷ୍ଟାର୍ଟ କରାଯାଉଛି…"</string>
<string name="reboot_to_reset_title" msgid="2226229680017882787">"ଫ୍ୟାକ୍ଟୋରୀ ଡାଟା ରିସେଟ୍"</string>
<string name="reboot_to_reset_message" msgid="3347690497972074356">"ରିଷ୍ଟାର୍ଟ କରାଯାଉଛି…"</string>
- <string name="shutdown_progress" msgid="5017145516412657345">"ବନ୍ଦ କରାଯାଉଛି…"</string>
+ <string name="shutdown_progress" msgid="5017145516412657345">"ବନ୍ଦ ହେଉଛି…"</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"ଆପଣଙ୍କ ଟାବଲେଟ୍ ବନ୍ଦ ହୋଇଯିବ।"</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"ଆପଣଙ୍କର Android TV ଡିଭାଇସ୍ ବନ୍ଦ ହୋଇଯିବ।"</string>
<string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"ଆପଣଙ୍କ ଘଣ୍ଟା ବନ୍ଦ ହୋଇଯିବ।"</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ"</string>
<string name="select_input_method" msgid="3971267998568587025">"ଇନପୁଟ୍ ପଦ୍ଧତି ବାଛନ୍ତୁ"</string>
<string name="show_ime" msgid="6406112007347443383">"ଫିଜିକାଲ୍ କୀବୋର୍ଡ ସକ୍ରିୟ ଥିବାବେଳେ ଏହାକୁ ସ୍କ୍ରିନ୍ ଉପରେ ରଖନ୍ତୁ"</string>
- <string name="hardware" msgid="1800597768237606953">"ଭର୍ଚୁଆଲ୍ କୀ’ବୋର୍ଡ ଦେଖାନ୍ତୁ"</string>
+ <string name="hardware" msgid="3611039921284836033">"ଅନ-ସ୍କ୍ରିନ କୀବୋର୍ଡ ବ୍ୟବହାର କର"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g>କୁ କନଫିଗର କରନ୍ତୁ"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ଫିଜିକାଲ କୀବୋର୍ଡଗୁଡ଼ିକୁ କନଫିଗର କରନ୍ତୁ"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ଭାଷା ଓ ଲେଆଉଟ ଚୟନ କରିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବର୍ତ୍ତମାନ ଉପଲବ୍ଧ ନାହିଁ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"ଅନୁମତି ଅନୁରୋଧକୁ ବନ୍ଦ କରାଯାଇଛି"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"କ୍ୟାମେରା ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ଫୋନରେ ଜାରି ରଖନ୍ତୁ"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ମାଇକ୍ରୋଫୋନ ଉପଲବ୍ଧ ନାହିଁ"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ Android TV ଡିଭାଇସରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଟାବଲେଟରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ବର୍ତ୍ତମାନ ଏହାକୁ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରେ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଫୋନରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"ଏହି ଆପ ଅତିରିକ୍ତ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି, ଏକ ଷ୍ଟ୍ରିମିଂ ସେସନରେ ଅନୁମତି ଦିଆଯାଇପାରିବ ନାହିଁ। ପ୍ରଥମେ ଆପଣଙ୍କ Android TV ଡିଭାଇସରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"ଏହି ଆପ ଅତିରିକ୍ତ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି, ଏକ ଷ୍ଟ୍ରିମିଂ ସେସନରେ ଅନୁମତି ଦିଆଯାଇପାରିବ ନାହିଁ। ପ୍ରଥମେ ଆପଣଙ୍କ ଟାବଲେଟରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"ଏହି ଆପ ଅତିରିକ୍ତ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି, ଏକ ଷ୍ଟ୍ରିମିଂ ସେସନରେ ଅନୁମତି ଦିଆଯାଇପାରିବ ନାହିଁ। ପ୍ରଥମେ ଆପଣଙ୍କ ଫୋନରେ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"ଏହି ଆପ ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ ଅନୁରୋଧ କରୁଛି। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ Android TV ଡିଭାଇସରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"ଏହି ଆପ ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ ଅନୁରୋଧ କରୁଛି। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଟାବଲେଟରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"ଏହି ଆପ ଅତିରିକ୍ତ ସୁରକ୍ଷା ପାଇଁ ଅନୁରୋଧ କରୁଛି। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଫୋନରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରୁ ଫୋନର କ୍ୟାମେରାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରୁ ଟାବଲେଟର କ୍ୟାମେରାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ଷ୍ଟ୍ରିମ କରିବା ସମୟରେ ଏହାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଫୋନରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ଷ୍ଟ୍ରିମ କରିବା ସମୟରେ ପିକଚର-ଇନ-ପିକଚର ଦେଖାଯାଇପାରିବ ନାହିଁ"</string>
<string name="system_locale_title" msgid="711882686834677268">"ସିଷ୍ଟମ ଡିଫଲ୍ଟ"</string>
<string name="default_card_name" msgid="9198284935962911468">"କାର୍ଡ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ୱାଚଗୁଡ଼ିକୁ ପରିଚାଳନା କରିବା ପାଇଁ ସହଯୋଗୀ ୱାଚ ପ୍ରୋଫାଇଲ ଅନୁମତି"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 68334fc..afcd67a 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="select_input_method" msgid="3971267998568587025">"ਇਨਪੁਟ ਵਿਧੀ ਚੁਣੋ"</string>
<string name="show_ime" msgid="6406112007347443383">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡ ਸਰਗਰਮ ਹੋਣ ਦੌਰਾਨ ਇਸ ਨੂੰ ਸਕ੍ਰੀਨ \'ਤੇ ਬਣਾਈ ਰੱਖੋ"</string>
- <string name="hardware" msgid="1800597768237606953">"ਆਭਾਸੀ ਕੀ-ਬੋਰਡ ਦਿਖਾਓ"</string>
+ <string name="hardware" msgid="3611039921284836033">"ਆਨ-ਸਕ੍ਰੀਨ ਕੀ-ਬੋਰਡ ਨੂੰ ਵਰਤੋ"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ਭੌਤਿਕ ਕੀ-ਬੋਰਡਾਂ ਦਾ ਸੰਰੂਪਣ ਕਰੋ"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"ਭਾਸ਼ਾ ਅਤੇ ਖਾਕਾ ਚੁਣਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"ਇਜਾਜ਼ਤ ਸੰਬੰਧੀ ਬੇਨਤੀ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"ਕੈਮਰਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ਫ਼ੋਨ \'ਤੇ ਜਾਰੀ ਰੱਖੋ"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਅਣਉਪਲਬਧ ਹੈ"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ Android TV ਡੀਵਾਈਸ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਟੈਬਲੈੱਟ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"ਇਸ ਸਮੇਂ ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> \'ਤੇ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"ਇਹ ਐਪ ਵਧੀਕ ਇਜਾਜ਼ਤਾਂ ਦੀ ਬੇਨਤੀ ਕਰ ਰਹੀ ਹੈ, ਪਰ ਸਟ੍ਰੀਮਿੰਗ ਸੈਸ਼ਨ ਵਿੱਚ ਇਜਾਜ਼ਤਾਂ ਨਹੀਂ ਦਿੱਤੀਆਂ ਜਾ ਸਕਦੀਆਂ। ਪਹਿਲਾਂ ਆਪਣੇ Android TV ਡੀਵਾਈਸ \'ਤੇ ਇਜਾਜ਼ਤ ਦਿਓ।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"ਇਹ ਐਪ ਵਧੀਕ ਇਜਾਜ਼ਤਾਂ ਦੀ ਬੇਨਤੀ ਕਰ ਰਹੀ ਹੈ, ਪਰ ਸਟ੍ਰੀਮਿੰਗ ਸੈਸ਼ਨ ਵਿੱਚ ਇਜਾਜ਼ਤਾਂ ਨਹੀਂ ਦਿੱਤੀਆਂ ਜਾ ਸਕਦੀਆਂ। ਪਹਿਲਾਂ ਆਪਣੇ ਟੈਬਲੈੱਟ \'ਤੇ ਇਜਾਜ਼ਤ ਦਿਓ।"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"ਇਹ ਐਪ ਵਧੀਕ ਇਜਾਜ਼ਤਾਂ ਦੀ ਬੇਨਤੀ ਕਰ ਰਹੀ ਹੈ, ਪਰ ਸਟ੍ਰੀਮਿੰਗ ਸੈਸ਼ਨ ਵਿੱਚ ਇਜਾਜ਼ਤਾਂ ਨਹੀਂ ਦਿੱਤੀਆਂ ਜਾ ਸਕਦੀਆਂ। ਪਹਿਲਾਂ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਇਜਾਜ਼ਤ ਦਿਓ।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"ਇਹ ਐਪ ਵਧੀਕ ਸੁਰੱਖਿਆ ਦੀ ਬੇਨਤੀ ਕਰ ਰਹੀ ਹੈ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ Android TV ਡੀਵਾਈਸ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"ਇਹ ਐਪ ਵਧੀਕ ਸੁਰੱਖਿਆ ਦੀ ਬੇਨਤੀ ਕਰ ਰਹੀ ਹੈ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਟੈਬਲੈੱਟ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"ਇਹ ਐਪ ਵਧੀਕ ਸੁਰੱਖਿਆ ਦੀ ਬੇਨਤੀ ਕਰ ਰਹੀ ਹੈ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਫ਼ੋਨ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਟੈਬਲੈੱਟ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ ਨਹੀਂ ਦੇਖੀ ਜਾ ਸਕਦੀ"</string>
<string name="system_locale_title" msgid="711882686834677268">"ਸਿਸਟਮ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
<string name="default_card_name" msgid="9198284935962911468">"ਕਾਰਡ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ਘੜੀਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਸੰਬੰਧੀ ਘੜੀ ਪ੍ਰੋਫਾਈਲ ਇਜਾਜ਼ਤ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index e0bcd67..8929505 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ODRZUĆ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Wybierz metodę wprowadzania"</string>
<string name="show_ime" msgid="6406112007347443383">"Pozostaw na ekranie, gdy aktywna jest klawiatura fizyczna"</string>
- <string name="hardware" msgid="1800597768237606953">"Pokaż klawiaturę wirtualną"</string>
+ <string name="hardware" msgid="3611039921284836033">"Używaj klawiatury ekranowej"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Skonfiguruj urządzenie <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Skonfiguruj klawiatury fizyczne"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Kliknij, aby wybrać język i układ"</string>
@@ -1961,8 +1961,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacja jest niedostępna"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest obecnie niedostępna."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – brak dostępu"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Zablokowana prośba o uprawnienia"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Aparat niedostępny"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Kontynuuj na telefonie"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon niedostępny"</string>
@@ -1973,12 +1972,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj urządzenia z Androidem TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj tabletu."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"W tej chwili nie można z tego skorzystać na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>. Użyj telefonu."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Ta aplikacja prosi o dodatkowe uprawnienia, ale nie można ich przyznać w trakcie sesji odtwarzania strumieniowego. Najpierw przyznaj te uprawnienia na urządzeniu z Androidem TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Ta aplikacja prosi o dodatkowe uprawnienia, ale nie można ich przyznać w trakcie sesji odtwarzania strumieniowego. Najpierw przyznaj te uprawnienia na tablecie."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Ta aplikacja prosi o dodatkowe uprawnienia, ale nie można ich przyznać w trakcie sesji odtwarzania strumieniowego. Najpierw przyznaj te uprawnienia na telefonie."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ta aplikacja wymaga dodatkowych zabezpieczeń. Użyj urządzenia z Androidem TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ta aplikacja wymaga dodatkowych zabezpieczeń. Użyj tabletu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ta aplikacja wymaga dodatkowych zabezpieczeń. Użyj telefonu."</string>
@@ -2322,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nie można korzystać z aparatu telefonu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nie można korzystać z aparatu tabletu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Nie można z tego skorzystać podczas strumieniowania. Użyj telefonu."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Podczas strumieniowania nie można wyświetlać obrazu w obrazie"</string>
<string name="system_locale_title" msgid="711882686834677268">"Ustawienie domyślne systemu"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Uprawnienie profilu zegarka towarzyszącego do zarządzania zegarkami"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 2d11772..09b3e4a8 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RECUSAR"</string>
<string name="select_input_method" msgid="3971267998568587025">"Selecione o método de entrada"</string>
<string name="show_ime" msgid="6406112007347443383">"Mantém o teclado virtual na tela enquanto o teclado físico está ativo"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostrar teclado virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Usar teclado na tela"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure o dispositivo <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure teclados físicos"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toque para selecionar o idioma e o layout"</string>
@@ -2317,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível acessar a câmera do smartphone pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível acessar a câmera do tablet pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Não é possível acessar esse conteúdo durante o streaming. Tente pelo smartphone."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível usar o modo picture-in-picture durante o streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"Padrão do sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"CHIP <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permissão do perfil do relógio complementar para gerenciar relógios"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f6d9771..283eb084 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RECUSAR"</string>
<string name="select_input_method" msgid="3971267998568587025">"Escolher o método de entrada"</string>
<string name="show_ime" msgid="6406112007347443383">"Manter no ecrã enquanto o teclado físico estiver ativo"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostrar o teclado virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Usar o teclado no ecrã"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure o dispositivo <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure teclados físicos"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toque para selecionar o idioma e o esquema"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string>
<string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> indisponível"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Pedido de autorização suprimido"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Câmara indisponível"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continue no telemóvel"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microfone indisponível"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no dispositivo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"De momento, não é possível aceder a esta app no seu <xliff:g id="DEVICE">%1$s</xliff:g>. Em alternativa, experimente no telemóvel."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Esta app está a pedir autorizações adicionais, mas não é possível conceder autorizações numa sessão de streaming. Comece por conceder a autorização no seu dispositivo Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Esta app está a pedir autorizações adicionais, mas não é possível conceder autorizações numa sessão de streaming. Comece por conceder a autorização no seu tablet."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Esta app está a pedir autorizações adicionais, mas não é possível conceder autorizações numa sessão de streaming. Comece por conceder a autorização no seu telemóvel."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta app está a solicitar segurança adicional. Em alternativa, experimente no dispositivo Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esta app está a solicitar segurança adicional. Em alternativa, experimente no tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esta app está a solicitar segurança adicional. Em alternativa, experimente no telemóvel."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível aceder à câmara do telemóvel a partir do dispositivo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível aceder à câmara do tablet a partir do dispositivo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Não é possível aceder a isto durante o streaming. Em alternativa, experimente no telemóvel."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível ver o ecrã no ecrã durante o streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"Predefinição do sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARTÃO <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Autorização do perfil de relógio associado para gerir relógios"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2d11772..09b3e4a8 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RECUSAR"</string>
<string name="select_input_method" msgid="3971267998568587025">"Selecione o método de entrada"</string>
<string name="show_ime" msgid="6406112007347443383">"Mantém o teclado virtual na tela enquanto o teclado físico está ativo"</string>
- <string name="hardware" msgid="1800597768237606953">"Mostrar teclado virtual"</string>
+ <string name="hardware" msgid="3611039921284836033">"Usar teclado na tela"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configure o dispositivo <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configure teclados físicos"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toque para selecionar o idioma e o layout"</string>
@@ -2317,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível acessar a câmera do smartphone pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível acessar a câmera do tablet pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Não é possível acessar esse conteúdo durante o streaming. Tente pelo smartphone."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível usar o modo picture-in-picture durante o streaming"</string>
<string name="system_locale_title" msgid="711882686834677268">"Padrão do sistema"</string>
<string name="default_card_name" msgid="9198284935962911468">"CHIP <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permissão do perfil do relógio complementar para gerenciar relógios"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index a38dacb..676eedf 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REFUZ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Alege metoda de introducere de text"</string>
<string name="show_ime" msgid="6406112007347443383">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
- <string name="hardware" msgid="1800597768237606953">"Afișează tastatura virtuală"</string>
+ <string name="hardware" msgid="3611039921284836033">"Folosește tastatura pe ecran"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Configurează <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Configurează tastaturi fizice"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Atinge pentru a selecta limba și aspectul"</string>
@@ -1954,14 +1954,13 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"Momentan, aplicația <xliff:g id="APP_NAME_0">%1$s</xliff:g> nu este disponibilă. Aceasta este gestionată de <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Află mai multe"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anulează întreruperea aplicației"</string>
- <string name="work_mode_off_title" msgid="6367463960165135829">"Reactivezi aplicații lucru?"</string>
+ <string name="work_mode_off_title" msgid="6367463960165135829">"Reactivezi aplicații de lucru?"</string>
<string name="work_mode_turn_on" msgid="5316648862401307800">"Reactivează"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Urgență"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nu este disponibilă"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Solicitarea de permisiune s-a suprimat"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Camera video nu este disponibilă"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continuă pe telefon"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microfon indisponibil"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încearcă pe dispozitivul Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încearcă pe tabletă."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Aplicația nu poate fi accesată pe <xliff:g id="DEVICE">%1$s</xliff:g> momentan. Încearcă pe telefon."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Aplicația solicită permisiuni suplimentare, dar acestea nu pot fi acordate într-o sesiune de streaming. Acordă permisiunea întâi pe dispozitivul Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Aplicația solicită permisiuni suplimentare, dar acestea nu pot fi acordate într-o sesiune de streaming. Acordă permisiunea întâi pe tabletă."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Aplicația solicită permisiuni suplimentare, dar acestea nu pot fi acordate într-o sesiune de streaming. Acordă permisiunea întâi pe telefon."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Aplicația necesită securitate suplimentară. Încearcă pe dispozitivul Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Aplicația necesită securitate suplimentară. Încearcă pe tabletă."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Aplicația necesită securitate suplimentară. Încearcă pe telefon."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nu se poate accesa camera foto a telefonului de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nu se poate accesa camera foto a tabletei de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Nu se poate accesa în timpul streamingului. Încearcă pe telefon."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Nu se poate viziona picture-in-picture în timpul streamingului"</string>
<string name="system_locale_title" msgid="711882686834677268">"Prestabilită de sistem"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Permisiunea pentru gestionarea ceasurilor din profilul ceasului însoțitor"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9dd5e4f..f5fc02c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ОТКЛОНИТЬ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Выберите способ ввода"</string>
<string name="show_ime" msgid="6406112007347443383">"Не скрывать экранную клавиатуру, когда включена физическая"</string>
- <string name="hardware" msgid="1800597768237606953">"Виртуальная клавиатура"</string>
+ <string name="hardware" msgid="3611039921284836033">"Использовать экранную клавиатуру"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Настройте устройство \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\""</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Настройте физические клавиатуры"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Нажмите, чтобы выбрать язык и раскладку"</string>
@@ -1961,8 +1961,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Приложение недоступно"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" сейчас недоступно."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Запрос разрешений заблокирован"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера недоступна"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продолжите на телефоне"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон недоступен"</string>
@@ -1973,12 +1972,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Эта функция пока недоступна на устройстве <xliff:g id="DEVICE">%1$s</xliff:g>. Используйте планшет."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"На устройстве <xliff:g id="DEVICE">%1$s</xliff:g> эта функция пока недоступна. Используйте телефон."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Это приложение запрашивает дополнительные разрешения, которые невозможно предоставить во время трансляции на устройство. Сначала откройте доступ на устройстве Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Это приложение запрашивает дополнительные разрешения, которые невозможно предоставить во время трансляции на устройство. Сначала откройте доступ на планшете."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Это приложение запрашивает дополнительные разрешения, которые невозможно предоставить во время трансляции на устройство. Сначала откройте доступ на телефоне."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Это приложение запрашивает дополнительные меры защиты. Используйте Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Это приложение запрашивает дополнительные меры защиты. Используйте планшет."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Это приложение запрашивает дополнительные меры защиты. Используйте телефон."</string>
@@ -2322,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"У устройства <xliff:g id="DEVICE">%1$s</xliff:g> нет доступа к камере телефона."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"У устройства \"<xliff:g id="DEVICE">%1$s</xliff:g>\" нет доступа к камере планшета."</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Этот контент недоступен во время трансляции. Используйте телефон."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Нельзя запустить режим \"Картинка в картинке\" во время потоковой передачи"</string>
<string name="system_locale_title" msgid="711882686834677268">"Системные настройки по умолчанию"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Разрешение для сопутствующего приложения управлять часами"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 92b7f51..c19c081 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ප්රතික්ෂේප කරන්න"</string>
<string name="select_input_method" msgid="3971267998568587025">"ආදාන ක්රමයක් තෝරන්න"</string>
<string name="show_ime" msgid="6406112007347443383">"භෞතික යතුරු පුවරුව සක්රිය අතරතුර එය තිරය මත තබා ගන්න"</string>
- <string name="hardware" msgid="1800597768237606953">"අතථ්ය යතුරු පුවරුව පෙන්වන්න"</string>
+ <string name="hardware" msgid="3611039921284836033">"තිරය මත යතුරු පුවරුව භාවිතය"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> වින්යාස කරන්න"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"භෞතික යතුරුපුවරුව වින්යාස කරන්න"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"භාෂාව හා පිරිසැලසුම තේරීමට තට්ටු කරන්න"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"යෙදුම ලබා ගත නොහැකිය"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> මේ දැන් ලබා ගත නොහැකිය."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> නොතිබේ"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"අවසර ඉල්ලීම වළක්වා ඇත"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"කැමරාව ලබා ගත නොහැකිය"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"දුරකථනයෙන් දිගටම කර ගෙන යන්න"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"මයික්රෆෝනය ලබා ගත නොහැකිය"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ Android TV උපාංගයෙහි උත්සාහ කරන්න."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ ටැබ්ලටයෙහි උත්සාහ කරන්න."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"මේ අවස්ථාවේදී මෙයට ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> හි ප්රවේශ විය නොහැකිය. ඒ වෙනුවට ඔබගේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"මෙම යෙදුම අතිරේක අවසර ඉල්ලා සිටින නමුත්, ප්රවාහ සැසියක අවසර ලබා දිය නොහැක. පළමුව ඔබේ Android TV උපාංගයෙන් අවසරය ලබා දෙන්න."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"මෙම යෙදුම අතිරේක අවසර ඉල්ලා සිටින නමුත්, ප්රවාහ සැසියක අවසර ලබා දිය නොහැක. පළමුව ඔබේ ටැබ්ලටයෙන් අවසරය ලබා දෙන්න."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"මෙම යෙදුම අතිරේක අවසර ඉල්ලා සිටින නමුත්, ප්රවාහ සැසියක අවසර ලබා දිය නොහැක. පළමුව ඔබේ දුරකථනයෙන් අවසරය ලබා දෙන්න."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"මෙම යෙදුම අමතර ආරක්ෂාවක් ඉල්ලා සිටී. ඒ වෙනුවට ඔබගේ Android TV උපාංගයෙහි උත්සාහ කරන්න."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"මෙම යෙදුම අමතර ආරක්ෂාවක් ඉල්ලා සිටී. ඒ වෙනුවට ඔබගේ ටැබ්ලටයෙහි උත්සාහ කරන්න."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"මෙම යෙදුම අමතර ආරක්ෂාවක් ඉල්ලා සිටී. ඒ වෙනුවට ඔබගේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් දුරකථනයේ කැමරාවට ප්රවේශ විය නොහැකිය"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් ටැබ්ලටයේ කැමරාවට ප්රවේශ විය නොහැකිය"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ප්රවාහය කරන අතරේ මෙයට ප්රවේශ විය නොහැක. ඒ වෙනුවට ඔබේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ප්රවාහය අතරේ පින්තූරයේ-පින්තූරය බැලිය නොහැක"</string>
<string name="system_locale_title" msgid="711882686834677268">"පද්ධති පෙරනිමිය"</string>
<string name="default_card_name" msgid="9198284935962911468">"කාඩ්පත <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"ඔරලෝසු කළමනාකරණය කිරීමට සහායක ඔරලෝසු පැතිකඩ අවසරය"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index f76c617..1d5288e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -231,7 +231,7 @@
<string name="reboot_to_update_reboot" msgid="4474726009984452312">"Reštartuje sa…"</string>
<string name="reboot_to_reset_title" msgid="2226229680017882787">"Obnovenie výrobných nastavení"</string>
<string name="reboot_to_reset_message" msgid="3347690497972074356">"Reštartuje sa…"</string>
- <string name="shutdown_progress" msgid="5017145516412657345">"Prebieha vypínanie..."</string>
+ <string name="shutdown_progress" msgid="5017145516412657345">"Vypína sa..."</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Váš tablet bude vypnutý."</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Zariadenie Android TV sa vypne."</string>
<string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"Hodinky sa vypnú."</string>
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ODMIETNUŤ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Zvoliť metódu vstupu"</string>
<string name="show_ime" msgid="6406112007347443383">"Ponechať na obrazovke, keď je aktívna fyzická klávesnica"</string>
- <string name="hardware" msgid="1800597768237606953">"Zobraziť virtuálnu klávesnicu"</string>
+ <string name="hardware" msgid="3611039921284836033">"Použiť klávesnicu na obrazovke"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Nakonfigurujte <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Nakonfigurujte fyzické klávesnice"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Klepnutím vyberte jazyk a rozloženie"</string>
@@ -1961,8 +1961,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikácia nie je dostupná"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> nie je teraz dostupná."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nie je k dispozícii"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Žiadosť o povolenie bola zablokovaná"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nie je k dispozícii"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Pokračujte v telefóne"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofón nie je k dispozícii"</string>
@@ -1973,12 +1972,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť zariadenie Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste použiť telefón."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Táto aplikácia požaduje ďalšie povolenia, ale povolenia nie je možné udeliť v relácii streamovania. Najprv udeľte povolenie v zariadení Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Táto aplikácia požaduje ďalšie povolenia, ale povolenia nie je možné udeliť v relácii streamovania. Najprv udeľte povolenie v tablete."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Táto aplikácia požaduje ďalšie povolenia, ale povolenia nie je možné udeliť v relácii streamovania. Najprv udeľte povolenie v telefóne."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Táto aplikácia požaduje dodatočné zabezpečenie. Skúste namiesto toho použiť zariadenie Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Táto aplikácia požaduje dodatočné zabezpečenie. Skúste namiesto toho použiť tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Táto aplikácia požaduje dodatočné zabezpečenie. Skúste použiť telefón."</string>
@@ -2322,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere telefónu"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere tabletu"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"K tomuto obsahu nie je počas streamovania prístup. Skúste použiť telefón."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Počas streamingu sa obraz v obraze nedá zobraziť"</string>
<string name="system_locale_title" msgid="711882686834677268">"Predvolené systémom"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Povolenie profilu hodiniek pre sprievodnú aplikáciu umožňujúce spravovať hodinky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 97dc284..3959ec6 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -231,7 +231,7 @@
<string name="reboot_to_update_reboot" msgid="4474726009984452312">"Vnovičen zagon …"</string>
<string name="reboot_to_reset_title" msgid="2226229680017882787">"Ponastavitev na tovarniške nastavitve"</string>
<string name="reboot_to_reset_message" msgid="3347690497972074356">"Vnovičen zagon …"</string>
- <string name="shutdown_progress" msgid="5017145516412657345">"Se zaustavlja ..."</string>
+ <string name="shutdown_progress" msgid="5017145516412657345">"Izklaplja se ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Tablični računalnik se bo zaustavil."</string>
<string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Naprava Android TV se bo zaustavila."</string>
<string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"Ura se bo izklopila."</string>
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"NE SPREJMEM"</string>
<string name="select_input_method" msgid="3971267998568587025">"Izberite način vnosa"</string>
<string name="show_ime" msgid="6406112007347443383">"Ohrani na zaslonu, dokler je aktivna fizična tipkovnica"</string>
- <string name="hardware" msgid="1800597768237606953">"Pokaži navidezno tipkovnico"</string>
+ <string name="hardware" msgid="3611039921284836033">"Uporaba zaslonske tipkovnice"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfiguriranje naprave <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfiguriranje fizičnih tipkovnic"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Dotaknite se, če želite izbrati jezik in postavitev."</string>
@@ -1961,8 +1961,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacija ni na voljo"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> trenutno ni na voljo."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"»<xliff:g id="ACTIVITY">%1$s</xliff:g>« ni na voljo"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Zahteva za dovoljenje je bila prezrta"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Fotoaparat ni na voljo"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Nadaljevanje v telefonu"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon ni na voljo"</string>
@@ -1973,12 +1972,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite z napravo Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite s tabličnim računalnikom."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V napravi <xliff:g id="DEVICE">%1$s</xliff:g> trenutno ni mogoče dostopati do te vsebine. Poskusite s telefonom."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Ta aplikacija zahteva dodatna dovoljenja, vendar teh ni mogoče odobriti med sejo pretočnega predvajanja. Dovoljenje najprej odobrite v napravi Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Ta aplikacija zahteva dodatna dovoljenja, vendar teh ni mogoče odobriti med sejo pretočnega predvajanja. Dovoljenje najprej odobrite v tabličnem računalniku."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Ta aplikacija zahteva dodatna dovoljenja, vendar teh ni mogoče odobriti med sejo pretočnega predvajanja. Dovoljenje najprej odobrite v telefonu."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ta aplikacija zahteva dodatno varnost. Poskusite z napravo Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ta aplikacija zahteva dodatno varnost. Poskusite s tabličnim računalnikom."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ta aplikacija zahteva dodatno varnost. Poskusite s telefonom."</string>
@@ -2322,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ni mogoče dostopati do fotoaparata telefona prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ni mogoče dostopati do fotoaparata tabličnega računalnika prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Do te vsebine ni mogoče dostopati med pretočnim predvajanjem. Poskusite s telefonom."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Slike v sliki ni mogoče prikazati med pretočnim predvajanjem."</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistemsko privzeto"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Dovoljenje za upravljanje ur v profilu ure v spremljevalni aplikaciji"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 3744696..d7ce6e4 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REFUZO"</string>
<string name="select_input_method" msgid="3971267998568587025">"Zgjidh metodën e hyrjes"</string>
<string name="show_ime" msgid="6406112007347443383">"Mbaje në ekran ndërsa tastiera fizike është aktive"</string>
- <string name="hardware" msgid="1800597768237606953">"Shfaq tastierën virtuale"</string>
+ <string name="hardware" msgid="3611039921284836033">"Përdor tastierën në ekran"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfiguro <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfiguro tastierat fizike"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Trokit për të zgjedhur gjuhën dhe strukturën"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Aplikacioni nuk ofrohet"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk ofrohet për momentin."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> nuk ofrohet"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Kërkesa për leje është ndaluar"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera nuk ofrohet"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Vazhdo në telefon"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofoni nuk ofrohet"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në pajisjen Android TV më mirë."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në tablet më mirë."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Qasja është e pamundur në <xliff:g id="DEVICE">%1$s</xliff:g> për momentin. Provoje në telefon më mirë."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Ky aplikacion po kërkon leje shtesë, por lejet nuk mund të jepen në një seancë transmetimi. Fillimisht jep lejen në pajisjen tënde Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Ky aplikacion po kërkon leje shtesë, por lejet nuk mund të jepen në një seancë transmetimi. Fillimisht jep lejen në tabletin tënd."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Ky aplikacion po kërkon leje shtesë, por lejet nuk mund të jepen në një seancë transmetimi. Fillimisht jep lejen në telefonin tënd."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ky aplikacion po kërkon siguri shtesë. Provoje në pajisjen Android TV më mirë."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ky aplikacion po kërkon siguri shtesë. Provoje në tablet më mirë."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ky aplikacion po kërkon siguri shtesë. Provoje në telefon më mirë."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nuk mund të qasesh në kamerën e telefonit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nuk mund të qasesh në kamerën e tabletit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Nuk mund të kesh qasje në të gjatë transmetimit. Provoje në telefon më mirë."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Figura brenda figurës nuk mund të shikohet gjatë transmetimit"</string>
<string name="system_locale_title" msgid="711882686834677268">"Parazgjedhja e sistemit"</string>
<string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Leje për profilin e \"Orës shoqëruese\" për të menaxhuar orët"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7bc4ee9..0aa2f38 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1397,7 +1397,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ОДБИЈ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Избор метода уноса"</string>
<string name="show_ime" msgid="6406112007347443383">"Задржава се на екрану док је физичка тастатура активна"</string>
- <string name="hardware" msgid="1800597768237606953">"Прикажи виртуелну тастатуру"</string>
+ <string name="hardware" msgid="3611039921284836033">"Користи тастатуру на екрану"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Конфигуришите уређај <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Конфигуришите физичке тастатуре"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Додирните да бисте изабрали језик и распоред"</string>
@@ -1960,8 +1960,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Апликација није доступна"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> тренутно није доступна."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> – није доступно"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Захтев за дозволу је блокиран"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера није доступна"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Наставите на телефону"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Микрофон је недоступан"</string>
@@ -1972,12 +1971,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на Android TV уређају."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на таблету."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Овој апликацији тренутно не може да се приступи са уређаја <xliff:g id="DEVICE">%1$s</xliff:g>. Пробајте на телефону."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Ова апликација захтева додатне дозволе, али дозволе не могу да се дају у сесији стримовања. Прво дајте дозволу на Android TV уређају."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Ова апликација захтева додатне дозволе, али дозволе не могу да се дају у сесији стримовања. Прво дајте дозволу на таблету."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Ова апликација захтева додатне дозволе, али дозволе не могу да се дају у сесији стримовања. Прво дајте дозволу на телефону."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ова апликација захтева додатну безбедност. Пробајте на Android TV уређају."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ова апликација захтева додатну безбедност. Пробајте на таблету."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ова апликација захтева додатну безбедност. Пробајте на телефону."</string>
@@ -2321,7 +2317,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се приступи камери телефона са <xliff:g id="DEVICE">%1$s</xliff:g> уређаја"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се приступи камери таблета са <xliff:g id="DEVICE">%1$s</xliff:g> уређаја"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Овом не можете да приступате током стримовања. Пробајте на телефону."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Не можете да гледате слику у слици при стримовању"</string>
<string name="system_locale_title" msgid="711882686834677268">"Подразумевани системски"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТИЦА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дозвола за профил пратећег сата за управљање сатовима"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f7c9058..6542c56 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"AVVISA"</string>
<string name="select_input_method" msgid="3971267998568587025">"Välj inmatningsmetod"</string>
<string name="show_ime" msgid="6406112007347443383">"Ha kvar det på skärmen när det fysiska tangentbordet används"</string>
- <string name="hardware" msgid="1800597768237606953">"Visa virtuellt tangentbord"</string>
+ <string name="hardware" msgid="3611039921284836033">"Använd skärmtangentbord"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Konfigurera <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Konfigurera fysiska tangentbord"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Tryck om du vill välja språk och layout"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Appen är inte tillgänglig"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> är inte tillgängligt just nu."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> är inte tillgänglig"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Begäran om behörighet har dolts"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kameran är inte tillgänglig"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Fortsätt på telefonen"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofonen är inte tillgänglig"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med Android TV-enheten i stället."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med surfplattan i stället."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Det går inte att streama detta till <xliff:g id="DEVICE">%1$s</xliff:g> för närvarande. Testa med telefonen i stället."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Appen begär ytterligare behörigheter, men det går inte att bevilja behörigheter under streamingsessionen. Bevilja behörigheten på Android TV-enheten först."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Appen begär ytterligare behörigheter, men det går inte att bevilja behörigheter under streamingsessionen. Bevilja behörigheten på surfplattan först."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Appen begär ytterligare behörigheter, men det går inte att bevilja behörigheter under streamingsessionen. Bevilja behörigheten på telefonen först."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Appen begär ytterligare säkerhet. Testa med Android TV-enheten i stället."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Appen begär ytterligare säkerhet. Testa med surfplattan i stället."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Appen begär ytterligare säkerhet. Testa med telefonen i stället."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Telefonens kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Surfplattans kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Det går inte att komma åt innehållet när du streamar. Testa med telefonen i stället."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Det går inte att visa bild-i-bild när du streamar"</string>
<string name="system_locale_title" msgid="711882686834677268">"Systemets standardinställning"</string>
<string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Behörighet för den tillhörande klockprofilen att hantera klockor"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index ac6ae4c..60d5907 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"KATAA"</string>
<string name="select_input_method" msgid="3971267998568587025">"Chagua njia ya ingizo"</string>
<string name="show_ime" msgid="6406112007347443383">"Ionyeshe kwenye skrini wakati kibodi halisi inatumika"</string>
- <string name="hardware" msgid="1800597768237606953">"Onyesha kibodi pepe"</string>
+ <string name="hardware" msgid="3611039921284836033">"Tumia kibodi ya skrini"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Wekea mipangilio <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Wekea kibodi halisi mipangilio"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Gusa ili uchague lugha na muundo"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Programu haipatikani"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> haipatikani hivi sasa."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> haipatikani"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Ombi la ruhusa limekataliwa"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera haipatikani"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Endelea kwenye simu"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Maikrofoni haipatikani"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye kifaa chako cha Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye kompyuta kibao yako."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Programu hii haiwezi kufikiwa kwenye <xliff:g id="DEVICE">%1$s</xliff:g> kwa muda huu. Badala yake jaribu kwenye simu yako."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Programu hii inaomba ruhusa za ziada. Hata hivyo, huwezi kutoa ruhusa ukitiririsha. Ruhusu kwanza kwenye kifaa chako cha Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Programu hii inaomba ruhusa za ziada. Hata hivyo, huwezi kutoa ruhusa ukitiririsha. Ruhusu kwenye kishikwambi chako kwanza."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Programu hii inaomba ruhusa za ziada. Hata hivyo, huwezi kutoa ruhusa ukitiririsha. Ruhusu kwenye simu yako kwanza."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Programu hii inaomba usalama wa ziada. Badala yake jaribu kwenye kifaa chako cha Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Programu hii inaomba usalama wa ziada. Badala yake jaribu kwenye kompyuta yako kibao."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Programu hii inaomba usalama wa ziada. Badala yake jaribu kwenye simu yako."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Huwezi kufikia kamera ya simu kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Haiwezi kufikia kamera ya kompyuta kibao kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Huwezi kufikia maudhui haya unapotiririsha. Badala yake jaribu kwenye simu yako."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Huwezi kuona picha iliyopachikwa ndani ya picha nyingine unapotiririsha"</string>
<string name="system_locale_title" msgid="711882686834677268">"Chaguomsingi la mfumo"</string>
<string name="default_card_name" msgid="9198284935962911468">"SIM KADI <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Ruhusa ya wasifu oanifu wa Saa ili kudhibiti saa"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 1d67c4a..cdfdca5 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"வேண்டாம்"</string>
<string name="select_input_method" msgid="3971267998568587025">"உள்ளீட்டு முறையைத் தேர்வுசெய்க"</string>
<string name="show_ime" msgid="6406112007347443383">"கைமுறை கீபோர்டு இயக்கத்தில் இருக்கும் போது IMEஐ திரையில் வைத்திரு"</string>
- <string name="hardware" msgid="1800597768237606953">"விர்ச்சுவல் கீபோர்டை காட்டு"</string>
+ <string name="hardware" msgid="3611039921284836033">"ஸ்கிரீன் கீபோர்டை உபயோகி"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> சாதனத்தை உள்ளமைத்தல்"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"கீபோர்டுகளை உள்ளமைத்தல்"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"மொழியையும் தளவமைப்பையும் தேர்ந்தெடுக்க, தட்டவும்"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"இந்த ஆப்ஸ் இப்போது கிடைப்பதில்லை"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் இப்போது கிடைப்பதில்லை."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> இல்லை"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"அணுகல் கோரிக்கை முடக்கப்பட்டது"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"கேமராவைப் பயன்படுத்த முடியாது"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"மொபைலில் தொடருங்கள்"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"மைக்ரோஃபோனைப் பயன்படுத்த முடியாது"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக Android TV சாதனத்தில் பயன்படுத்திப் பாருங்கள்."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் டேப்லெட்டில் பயன்படுத்திப் பாருங்கள்."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"தற்போது உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தில் இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் மொபைலில் பயன்படுத்திப் பாருங்கள்."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"இந்த ஆப்ஸ் கூடுதல் அனுமதிகளைக் கோருகிறது. ஆனால் ஸ்ட்ரீமிங் அமர்வில் அனுமதிகள் வழங்கப்படாது. முதலில் உங்கள் Android TV சாதனத்தில் அனுமதி வழங்கவும்."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"இந்த ஆப்ஸ் கூடுதல் அனுமதிகளைக் கோருகிறது. ஆனால் ஸ்ட்ரீமிங் அமர்வில் அனுமதிகள் வழங்கப்படாது. முதலில் உங்கள் டேப்லெட்டில் அனுமதி வழங்கவும்."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"இந்த ஆப்ஸ் கூடுதல் அனுமதிகளைக் கோருகிறது. ஆனால் ஸ்ட்ரீமிங் அமர்வில் அனுமதிகள் வழங்கப்படாது. முதலில் உங்கள் மொபைலில் அனுமதி வழங்கவும்."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"இந்த ஆப்ஸ் கூடுதல் பாதுகாப்பைக் கோருகிறது. அதற்குப் பதிலாக உங்கள் Android TV சாதனத்தில் பயன்படுத்திப் பார்க்கவும்."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"இந்த ஆப்ஸ் கூடுதல் பாதுகாப்பைக் கோருகிறது. அதற்குப் பதிலாக உங்கள் டேப்லெட்டில் பயன்படுத்திப் பார்க்கவும்."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"இந்த ஆப்ஸ் கூடுதல் பாதுகாப்பைக் கோருகிறது. அதற்குப் பதிலாக உங்கள் மொபைலில் பயன்படுத்திப் பார்க்கவும்."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்திலிருந்து மொபைலின் கேமராவை அணுக முடியாது"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்திலிருந்து டேப்லெட்டின் கேமராவை அணுக முடியாது"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"ஸ்ட்ரீமின்போது இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் மொபைலில் பயன்படுத்திப் பார்க்கவும்."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ஸ்ட்ரீம் செய்யும்போது பிக்ச்சர்-இன்-பிக்ச்சர் அம்சத்தைப் பயன்படுத்த முடியாது"</string>
<string name="system_locale_title" msgid="711882686834677268">"சிஸ்டத்தின் இயல்பு"</string>
<string name="default_card_name" msgid="9198284935962911468">"கார்டு <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"வாட்ச்சுகளை நிர்வகிக்க, துணைத் தயாரிப்பு ஆப்ஸில் வாட்ச் சுயவிவரத்தை அனுமதித்தல்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 7e3cfc1..3310cd8 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -659,7 +659,7 @@
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string>
<string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"వేలిముద్ర సెన్సార్ను ఉపయోగించడం సాధ్యం కాదు. రిపెయిర్ ప్రొవైడర్ను సందర్శించండి"</string>
<string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Power button pressed"</string>
- <string name="fingerprint_name_template" msgid="8941662088160289778">"వేలు <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>వ వేలు"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"వేలిముద్రను ఉపయోగించండి"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"వేలిముద్ర లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string>
<string name="fingerprint_dialog_default_subtitle" msgid="3879832845486835905">"కొనసాగించడానికి మీ వేలిముద్రను ఉపయోగించండి"</string>
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"తిరస్కరిస్తున్నాను"</string>
<string name="select_input_method" msgid="3971267998568587025">"ఇన్పుట్ పద్ధతిని ఎంచుకోండి"</string>
<string name="show_ime" msgid="6406112007347443383">"దీన్ని భౌతిక కీబోర్డ్ యాక్టివ్గా ఉన్నప్పుడు స్క్రీన్పై ఉంచుతుంది"</string>
- <string name="hardware" msgid="1800597768237606953">"వర్చువల్ కీబోర్డ్ను చూపు"</string>
+ <string name="hardware" msgid="3611039921284836033">"స్క్రీన్పై కీబోర్డ్ ఉపయోగించు"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g>ను కాన్ఫిగర్ చేయండి"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"ఫిజికల్ కీబోర్డ్లను కాన్ఫిగర్ చేయండి"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"భాషను, లేఅవుట్ను ఎంచుకోవడానికి ట్యాప్ చేయండి"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"మీ <xliff:g id="DEVICE">%1$s</xliff:g> నుండి ఫోన్ కెమెరాను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"మీ <xliff:g id="DEVICE">%1$s</xliff:g> నుండి టాబ్లెట్ కెమెరాను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"స్ట్రీమింగ్ చేస్తున్నప్పుడు దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ ఫోన్లో ట్రై చేయండి."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"స్ట్రీమింగ్ చేస్తున్నప్పుడు పిక్చర్-ఇన్-పిక్చర్ చూడలేరు"</string>
<string name="system_locale_title" msgid="711882686834677268">"సిస్టమ్ ఆటోమేటిక్ సెట్టింగ్"</string>
<string name="default_card_name" msgid="9198284935962911468">"కార్డ్ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"వాచ్లను మేనేజ్ చేయడానికి సహాయక వాచ్ ప్రొఫైల్ అనుమతి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 512b526..346c090 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ปฏิเสธ"</string>
<string name="select_input_method" msgid="3971267998568587025">"เลือกวิธีการป้อนข้อมูล"</string>
<string name="show_ime" msgid="6406112007347443383">"เปิดทิ้งไว้บนหน้าจอในระหว่างใช้งานแป้นพิมพ์จริง"</string>
- <string name="hardware" msgid="1800597768237606953">"แสดงแป้นพิมพ์เสมือน"</string>
+ <string name="hardware" msgid="3611039921284836033">"ใช้แป้นพิมพ์บนหน้าจอ"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"กำหนดค่า <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"กำหนดค่าแป้นพิมพ์จริง"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"แตะเพื่อเลือกภาษาและรูปแบบ"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"แอปไม่พร้อมใช้งาน"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่พร้อมใช้งานในขณะนี้"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> ไม่พร้อมใช้งาน"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"ระงับคำขอสิทธิ์อยู่"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"กล้องไม่พร้อมใช้งาน"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"ดำเนินการต่อบนโทรศัพท์"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"ไมโครโฟนไม่พร้อมใช้งาน"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในอุปกรณ์ Android TV แทน"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในแท็บเล็ตแทน"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"เข้าถึงแอปนี้ใน <xliff:g id="DEVICE">%1$s</xliff:g> ของคุณไม่ได้ในขณะนี้ โปรดลองเข้าถึงในโทรศัพท์แทน"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"แอปนี้มีการขอสิทธิ์เพิ่มเติม แต่ไม่สามารถให้สิทธิ์ในเซสชันที่สตรีมอยู่ โปรดให้สิทธิ์ในอุปกรณ์ Android TV ก่อน"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"แอปนี้มีการขอสิทธิ์เพิ่มเติม แต่ไม่สามารถให้สิทธิ์ในเซสชันที่สตรีมอยู่ โปรดให้สิทธิ์ในแท็บเล็ตก่อน"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"แอปนี้มีการขอสิทธิ์เพิ่มเติม แต่ไม่สามารถให้สิทธิ์ในเซสชันที่สตรีมอยู่ โปรดให้สิทธิ์ในโทรศัพท์ก่อน"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"แอปนี้มีการขอการรักษาความปลอดภัยเพิ่มเติม โปรดลองเข้าถึงในอุปกรณ์ Android TV แทน"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"แอปนี้มีการขอการรักษาความปลอดภัยเพิ่มเติม โปรดลองเข้าถึงในแท็บเล็ตแทน"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"แอปนี้มีการขอการรักษาความปลอดภัยเพิ่มเติม โปรดลองเข้าถึงในโทรศัพท์แทน"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"เข้าถึงกล้องของโทรศัพท์จาก <xliff:g id="DEVICE">%1$s</xliff:g> ไม่ได้"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"เข้าถึงกล้องของแท็บเล็ตจาก <xliff:g id="DEVICE">%1$s</xliff:g> ไม่ได้"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"เข้าถึงเนื้อหานี้ไม่ได้ขณะที่สตรีมมิง โปรดลองเข้าถึงในโทรศัพท์แทน"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"ดูการแสดงภาพซ้อนภาพขณะสตรีมไม่ได้"</string>
<string name="system_locale_title" msgid="711882686834677268">"ค่าเริ่มต้นของระบบ"</string>
<string name="default_card_name" msgid="9198284935962911468">"ซิมการ์ด <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"สิทธิ์สำหรับโปรไฟล์ในนาฬิกาที่ใช้ร่วมกันเพื่อจัดการนาฬิกา"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index c6fe8d3..415c9ac 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"TANGGIHAN"</string>
<string name="select_input_method" msgid="3971267998568587025">"Pumili ng pamamaraan ng pag-input"</string>
<string name="show_ime" msgid="6406112007347443383">"Panatilihin ito sa screen habang aktibo ang pisikal na keyboard"</string>
- <string name="hardware" msgid="1800597768237606953">"Ipakita ang virtual keyboard"</string>
+ <string name="hardware" msgid="3611039921284836033">"Gumamit ng on-screen keyboard"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"I-configure ang <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"I-configure ang mga pisikal na keyboard"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"I-tap upang pumili ng wika at layout"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Hindi available ang app"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Hindi available sa ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Hindi available ang <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Na-suppress ang kahilingan sa pahintulot"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Hindi available ang camera"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Magpatuloy sa telepono"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Hindi available ang mikropono"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong Android TV device."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong tablet."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hindi ito maa-access sa iyong <xliff:g id="DEVICE">%1$s</xliff:g> sa ngayon. Subukan na lang sa iyong telepono."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Humihingi ang app na ito ng dagdag na pahintulot, pero hindi puwedeng ibigay ang mga pahintulot sa isang session ng streaming. Ibigay muna ang pahintulot sa iyong Android TV device."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Humihingi ang app na ito ng dagdag na pahintulot, pero hindi puwedeng ibigay ang mga pahintulot sa isang session ng streaming. Ibigay muna ang pahintulot sa iyong tablet."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Humihingi ang app na ito ng dagdag na pahintulot, pero hindi puwedeng ibigay ang mga pahintulot sa isang session ng streaming. Ibigay muna ang pahintulot sa iyong telepono."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Humihiling ng karagdagang seguridad ang app na ito. Subukan na lang sa iyong Android TV device."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Humihiling ng karagdagang seguridad ang app na ito. Subukan na lang sa iyong tablet."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Humihiling ng karagdagang seguridad ang app na ito. Subukan na lang sa iyong telepono."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Hindi ma-access ang camera ng telepono mula sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Hindi ma-access ang camera ng tablet mula sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Hindi ito puwedeng i-access habang nagsi-stream. Subukan na lang sa iyong telepono."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Hindi matingnan nang picture-in-picture habang nagsi-stream"</string>
<string name="system_locale_title" msgid="711882686834677268">"Default ng system"</string>
<string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Pahintulot sa profile ng Relo ng kasamang app na pamahalaan ang mga relo"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 32e85d91..b411429 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REDDET"</string>
<string name="select_input_method" msgid="3971267998568587025">"Giriş yöntemini seçin"</string>
<string name="show_ime" msgid="6406112007347443383">"Fiziksel klavye etkin durumdayken ekranda tut"</string>
- <string name="hardware" msgid="1800597768237606953">"Sanal klavyeyi göster"</string>
+ <string name="hardware" msgid="3611039921284836033">"Ekran klavyesi kullanın"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> ayarlarını yapılandır"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Fiziksel klavyeleri yapılandırın"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Dili ve düzeni seçmek için dokunun"</string>
@@ -1953,14 +1953,13 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> uygulaması şu anda kullanılamıyor. Uygulamanın kullanım durumu <xliff:g id="APP_NAME_1">%2$s</xliff:g> tarafından yönetiliyor."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Daha fazla bilgi"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Uygulamanın duraklatmasını kaldır"</string>
- <string name="work_mode_off_title" msgid="6367463960165135829">"İş uygulamaları açılsın mı?"</string>
+ <string name="work_mode_off_title" msgid="6367463960165135829">"İş uygulamaları devam ettirilsin mi?"</string>
<string name="work_mode_turn_on" msgid="5316648862401307800">"Devam ettir"</string>
<string name="work_mode_emergency_call_button" msgid="6818855962881612322">"Acil durum"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"Uygulama kullanılamıyor"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması şu anda kullanılamıyor."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kullanılamıyor"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"İzin isteği reddedildi"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera kullanılamıyor"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"İşleme telefonda devam edin"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon kullanılamıyor"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine Android TV cihazınızı kullanmayı deneyin."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine tabletinizi kullanmayı deneyin."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Bu uygulamaya şu anda <xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan erişilemiyor. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Bu uygulama ek izinler istiyor ancak akış oturumundayken izin verilemez. Önce Android TV cihazınızda ilgili izni verin."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Bu uygulama ek izinler istiyor ancak akış oturumundayken izin verilemez. Önce tabletinizde ilgili izni verin."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Bu uygulama ek izinler istiyor ancak akış oturumundayken izin verilemez. Önce telefonunuzda ilgili izni verin."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Bu uygulama daha fazla güvenlik istiyor. Bunun yerine Android TV cihazınızı kullanmayı deneyin."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Bu uygulama daha fazla güvenlik istiyor. Bunun yerine tabletinizi kullanmayı deneyin."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Bu uygulama daha fazla güvenlik istiyor. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına erişilemiyor"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan tabletin kamerasına erişilemiyor"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Canlı oynatılırken bu içeriğe erişilemez. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Yayın sırasında pencere içinde pencere görüntülenemez"</string>
<string name="system_locale_title" msgid="711882686834677268">"Sistem varsayılanı"</string>
<string name="default_card_name" msgid="9198284935962911468">"KART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Kol saatlerinin yönetimi için Tamamlayıcı Kol Saati Profili İzni"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index fc975f4..4f97154 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -675,7 +675,7 @@
<string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Натисніть, щоб видалити свою модель обличчя, а потім знову додайте її"</string>
<string name="face_setup_notification_title" msgid="8843461561970741790">"Налаштування фейс-контролю"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Ви зможете розблоковувати телефон, подивившись на нього"</string>
- <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Щоб використовувати фейсконтроль, увімкніть "<b>"Доступ до камери"</b>" в розділі \"Налаштування\" > \"Конфіденційність\""</string>
+ <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Щоб використовувати фейс-контроль, увімкніть "<b>"Доступ до камери"</b>" в розділі \"Налаштування\" > \"Конфіденційність\""</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Налаштуйте більше способів розблокування"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Натисніть, щоб додати відбиток пальця"</string>
<string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Розблокування відбитком пальця"</string>
@@ -719,12 +719,12 @@
<string name="face_error_lockout_permanent" msgid="8533257333130473422">"Забагато спроб. Фейс-контроль недоступний."</string>
<string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Забагато спроб. Розблокуйте екран іншим способом."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Не вдається перевірити обличчя. Повторіть спробу."</string>
- <string name="face_error_not_enrolled" msgid="1134739108536328412">"Ви не налаштували фейсконтроль"</string>
- <string name="face_error_hw_not_present" msgid="7940978724978763011">"Фейсконтроль не підтримується на цьому пристрої"</string>
+ <string name="face_error_not_enrolled" msgid="1134739108536328412">"Ви не налаштували фейс-контроль"</string>
+ <string name="face_error_hw_not_present" msgid="7940978724978763011">"Фейс-контроль не підтримується на цьому пристрої"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик тимчасово вимкнено."</string>
<string name="face_name_template" msgid="3877037340223318119">"Обличчя <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="5854024256907828015">"Доступ через фейсконтроль"</string>
- <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Використовувати фейсконтроль або дані для розблокування екрана"</string>
+ <string name="face_app_setting_name" msgid="5854024256907828015">"Доступ через фейс-контроль"</string>
+ <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Використовувати фейс-контроль або дані для розблокування екрана"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Щоб продовжити, скористайтеся фейсконтролем"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Щоб продовжити, скористайтеся фейсконтролем або даними для розблокування екрана"</string>
<string-array name="face_error_vendor">
@@ -976,7 +976,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторіть спробу"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Повторіть спробу"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Розблокуйте, щоб бачити всі функції й дані"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Перевищено максимальну кількість спроб розблокування за допомогою функції \"Фейсконтроль\""</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Перевищено максимальну кількість спроб розблокування за допомогою функції \"Фейс-контроль\""</string>
<string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"Немає SIM-карти"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"У планшеті немає SIM-карти."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="3903140876952198273">"У пристрої Android TV немає SIM-карти."</string>
@@ -1398,7 +1398,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"ВІДХИЛИТИ"</string>
<string name="select_input_method" msgid="3971267998568587025">"Вибрати метод введення"</string>
<string name="show_ime" msgid="6406112007347443383">"Утримуйте на екрані, коли активна фізична клавіатура"</string>
- <string name="hardware" msgid="1800597768237606953">"Показати віртуальну клавіатуру"</string>
+ <string name="hardware" msgid="3611039921284836033">"Екранна клавіатура"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Налаштуйте клавіатуру \"<xliff:g id="DEVICE_NAME">%s</xliff:g>\""</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Налаштуйте фізичні клавіатури"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Торкніться, щоб вибрати мову та розкладку"</string>
@@ -1961,8 +1961,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Додаток недоступний"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> зараз недоступний."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Недоступно: <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Запит на доступ відхилено"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Камера недоступна"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Продовжте на телефоні"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Мікрофон недоступний"</string>
@@ -1973,12 +1972,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися пристроєм Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися планшетом."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Цей додаток зараз недоступний на вашому <xliff:g id="DEVICE">%1$s</xliff:g>. Спробуйте натомість скористатися телефоном."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Цьому додатку потрібні додаткові дозволи, але їх не можна надати під час потокового передавання. Спершу надайте дозвіл на пристрої Android TV."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Цьому додатку потрібні додаткові дозволи, але їх не можна надати під час потокового передавання. Спершу надайте дозвіл на планшеті."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Цьому додатку потрібні додаткові дозволи, але їх не можна надати під час потокового передавання. Спершу надайте дозвіл на телефоні."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Цьому додатку потрібен додатковий рівень безпеки. Спробуйте натомість скористатися пристроєм Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Цьому додатку потрібен додатковий рівень безпеки. Спробуйте натомість скористатися планшетом."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Цьому додатку потрібен додатковий рівень безпеки. Спробуйте натомість скористатися телефоном."</string>
@@ -2322,7 +2318,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не вдається отримати доступ до камери телефона з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не вдається отримати доступ до камери планшета з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Цей контент недоступний під час потокового передавання. Спробуйте натомість скористатися телефоном."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ви не можете переглядати картинку в картинці під час трансляції"</string>
<string name="system_locale_title" msgid="711882686834677268">"Налаштування системи за умовчанням"</string>
<string name="default_card_name" msgid="9198284935962911468">"КАРТКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Дозвіл профілю годинника для супутнього додатка на керування годинниками"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 01858b8..b47bcb1 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"مسترد کریں"</string>
<string name="select_input_method" msgid="3971267998568587025">"ان پٹ کا طریقہ منتخب کریں"</string>
<string name="show_ime" msgid="6406112007347443383">"جب فزیکل کی بورڈ فعال ہو تو IME کو اسکرین پر رکھیں"</string>
- <string name="hardware" msgid="1800597768237606953">"ورچوئل کی بورڈ دکھائیں"</string>
+ <string name="hardware" msgid="3611039921284836033">"آن اسکرین کی بورڈ استعمال کریں"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"<xliff:g id="DEVICE_NAME">%s</xliff:g> کنفیگر کریں"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"فزیکل کی بورڈز کنفیگر کریں"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"زبان اور لے آؤٹ منتخب کرنے کیلئے تھپتھپائیں"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"ایپ دستیاب نہیں ہے"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> دستیاب نہیں ہے"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"اجازت کی درخواست دبا دی گئی"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"کیمرا دستیاب نہیں ہے"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"فون پر جاری رکھیں"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"مائیکروفون دستیاب نہیں ہے"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے Android TV آلے پر کوشش کریں۔"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے ٹیبلیٹ پر کوشش کریں۔"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"اس وقت آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> پر اس تک رسائی نہیں مل سکتی۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"یہ ایپ اضافی اجازتوں کی درخواست کر رہی ہے، لیکن سلسلہ بندی کے سیشن میں اجازتیں نہیں دی جا سکتیں۔ پہلے اپنے Android TV آلہ پر اجازت دیں۔"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"یہ ایپ اضافی اجازتوں کی درخواست کر رہی ہے، لیکن سلسلہ بندی کے سیشن میں اجازتیں نہیں دی جا سکتیں۔ پہلے اپنے ٹیبلیٹ پر اجازت دیں۔"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"یہ ایپ اضافی اجازتوں کی درخواست کر رہی ہے، لیکن سلسلہ بندی کے سیشن میں اجازتیں نہیں دی جا سکتیں۔ پہلے اپنے فون پر اجازت دیں۔"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"یہ ایپ اضافی سیکیورٹی کی درخواست کر رہی ہے۔ اس کے بجائے اپنے Android TV آلے پر کوشش کریں۔"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"یہ ایپ اضافی سیکیورٹی کی درخواست کر رہی ہے۔ اس کے بجائے اپنے ٹیبلیٹ پر کوشش کریں۔"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"یہ ایپ اضافی سیکیورٹی کی درخواست کر رہی ہے۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> سے فون کے کیمرا تک رسائی حاصل نہیں کی جا سکتی"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> سے ٹیبلیٹ کے کیمرا تک رسائی حاصل نہیں کی جا سکتی"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"سلسلہ بندی کے دوران اس تک رسائی حاصل نہیں کی جا سکتی۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"سلسلہ بندی کے دوران تصویر میں تصویر نہیں دیکھ سکتے"</string>
<string name="system_locale_title" msgid="711882686834677268">"سسٹم ڈیفالٹ"</string>
<string name="default_card_name" msgid="9198284935962911468">"کارڈ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"گھڑیوں کا نظم کرنے کے لیے ساتھی ایپ کی گھڑی کی پروفائل کی اجازت"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index cfaeca4..680b2a6 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RAD ETISH"</string>
<string name="select_input_method" msgid="3971267998568587025">"Matn kiritish usulini tanlang"</string>
<string name="show_ime" msgid="6406112007347443383">"Tashqi klaviatura ulanganida ekranda chiqib turadi"</string>
- <string name="hardware" msgid="1800597768237606953">"Virtual klaviatura"</string>
+ <string name="hardware" msgid="3611039921284836033">"Ekrandagi klaviatura"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Sozlang: <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Tashqi klaviaturalarni sozlang"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Til va sxemani belgilash uchun bosing"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Ilova ishlamayapti"</string>
<string name="app_blocked_message" msgid="542972921087873023">"Ayni vaqtda <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi ishlamayapti."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> kanali ish faoliyatida emas"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Ruxsat talabi bostirildi"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Kamera ishlamayapti"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Telefonda davom ettirish"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Mikrofon ishlamayapti"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Android TV qurilmasi orqali urinib koʻring."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Planshet orqali urinib koʻring."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Ayni vaqtda bu translatsiya <xliff:g id="DEVICE">%1$s</xliff:g> qurilmangizda ishlamaydi. Telefon orqali urininb koʻring."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Bu ilova qoʻshimcha ruxsatlar talab qilmoqda, lekin ruxsatlar striming seansida berilmaydi. Avval Android TV qurilmangizga ruxsat bering."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Bu ilova qoʻshimcha ruxsatlar talab qilmoqda, lekin ruxsatlar striming seansida berilmaydi. Avval planshetingizda ruxsat bering."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Bu ilova qoʻshimcha ruxsatlar talab qilmoqda, lekin ruxsatlar striming seansida berilmaydi. Avval telefoningizda ruxsat bering."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Bu ilova qoʻshimcha himoyani talab qilmoqda. Android TV qurilmasi orqali urinib koʻring."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Bu ilova qoʻshimcha himoyani talab qilmoqda. Planshet orqali urinib koʻring."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Bu ilova qoʻshimcha himoyani talab qilmoqda. Telefon orqali urininb koʻring."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> qurilmasidan telefonning kamerasiga kirish imkonsiz"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> qurilmasidan planshetning kamerasiga kirish imkonsiz"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Bu kontent striming vaqtida ochilmaydi. Telefon orqali urininb koʻring."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Striming vaqtida tasvir ustida tasvir rejimida koʻrib boʻlmaydi"</string>
<string name="system_locale_title" msgid="711882686834677268">"Tizim standarti"</string>
<string name="default_card_name" msgid="9198284935962911468">"SIM KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Soatlarni boshqarish uchun hamroh Soat profiliga ruxsat"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 4b03591..8b28907 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"TỪ CHỐI"</string>
<string name="select_input_method" msgid="3971267998568587025">"Chọn phương thức nhập"</string>
<string name="show_ime" msgid="6406112007347443383">"Hiện bàn phím ảo trên màn hình trong khi bàn phím vật lý đang hoạt động"</string>
- <string name="hardware" msgid="1800597768237606953">"Hiện bàn phím ảo"</string>
+ <string name="hardware" msgid="3611039921284836033">"Sử dụng bàn phím ảo"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Định cấu hình <xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Định cấu hình bàn phím vật lý"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Nhấn để chọn ngôn ngữ và bố cục"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Ứng dụng này không dùng được"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện không dùng được."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"Không hỗ trợ <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Yêu cầu quyền đã bị chặn"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Không dùng được máy ảnh"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Tiếp tục trên điện thoại"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Không dùng được micrô"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên thiết bị Android TV."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên máy tính bảng."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên điện thoại."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Ứng dụng này đang yêu cầu thêm quyền, nhưng bạn không thể cấp quyền trong một phiên truyền trực tuyến. Trước tiên, hãy cấp quyền trên thiết bị Android TV của bạn."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Ứng dụng này đang yêu cầu thêm quyền, nhưng bạn không thể cấp quyền trong một phiên truyền trực tuyến. Trước tiên, hãy cấp quyền trên máy tính bảng của bạn."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Ứng dụng này đang yêu cầu thêm quyền, nhưng bạn không thể cấp quyền trong một phiên truyền trực tuyến. Trước tiên, hãy cấp quyền trên điện thoại của bạn."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Ứng dụng này đang yêu cầu tính năng bảo mật bổ sung. Hãy thử trên thiết bị Android TV."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Ứng dụng này đang yêu cầu tính năng bảo mật bổ sung. Hãy thử trên máy tính bảng."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Ứng dụng này đang yêu cầu tính năng bảo mật bổ sung. Hãy thử trên điện thoại."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Không truy cập được vào máy ảnh trên điện thoại từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Không truy cập được vào máy ảnh trên máy tính bảng từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Bạn không thể truy cập vào nội dung này trong khi phát trực tuyến. Hãy thử trên điện thoại."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Không thể xem video ở chế độ hình trong hình khi đang truyền trực tuyến"</string>
<string name="system_locale_title" msgid="711882686834677268">"Theo chế độ mặc định của hệ thống"</string>
<string name="default_card_name" msgid="9198284935962911468">"THẺ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Quyền sử dụng hồ sơ Đồng hồ của ứng dụng đồng hành để quản lý các đồng hồ"</string>
diff --git a/core/res/res/values-watch/dimens.xml b/core/res/res/values-watch/dimens.xml
index c7caa39..bbca987 100644
--- a/core/res/res/values-watch/dimens.xml
+++ b/core/res/res/values-watch/dimens.xml
@@ -25,4 +25,12 @@
<dimen name="aerr_list_item_height">52dp</dimen>
<!-- Padding for contents in a view of BaseErrorDialog such as a title and buttons -->
<dimen name="base_error_dialog_contents_padding">14dp</dimen>
+
+ <!-- Specifies height of the divider in the input method chooser -->
+ <dimen name="input_method_divider_height">4dp</dimen>
+
+ <!-- The width/height of the icon view on staring surface. -->
+ <dimen name="starting_surface_icon_size">48dp</dimen>
+ <!-- The default width/height of the icon on the spec of adaptive icon drawable. -->
+ <dimen name="starting_surface_default_icon_size">48dp</dimen>
</resources>
diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml
index e44eda3..6d6cfc7 100644
--- a/core/res/res/values-watch/strings.xml
+++ b/core/res/res/values-watch/strings.xml
@@ -27,4 +27,7 @@
<!-- Reboot to Recovery Progress Dialog. This is shown before it reboots to recovery. -->
<string name="reboot_to_update_title">Wear OS system update</string>
-</resources>
\ No newline at end of file
+
+ <!-- Title of the pop-up dialog in which the user switches keyboard, also known as input method. -->
+ <string name="select_input_method">Choose input</string>
+</resources>
diff --git a/core/res/res/values-watch/styles.xml b/core/res/res/values-watch/styles.xml
index 6e84f39..4a7d57d 100644
--- a/core/res/res/values-watch/styles.xml
+++ b/core/res/res/values-watch/styles.xml
@@ -58,4 +58,22 @@
<item name="drawableTint">@android:color/white</item>
<item name="drawableTintMode">src_atop</item>
</style>
+
+ <!-- @hide -->
+ <style name="InputMethodSwitchHardKeyboardText">
+ <item name="paddingStart">?attr/listPreferredItemPaddingStart</item>
+ <item name="paddingEnd">16dp</item>
+ <item name="paddingTop">16dp</item>
+ <item name="paddingBottom">5dp</item>
+ <item name="minHeight">?attr/listPreferredItemHeightSmall</item>
+ </style>
+
+ <!-- @hide -->
+ <style name="InputMethodSwitchHardKeyboardSwitch">
+ <item name="layout_marginEnd">?attr/listPreferredItemPaddingEnd</item>
+ </style>
+
+ <style name="InputMethodSwitchDialogStyle" parent="AlertDialog.DeviceDefault">
+ <item name="android:listLayout">@layout/input_method_switcher_list_layout</item>
+ </style>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 19a34c6..c427065 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"拒绝"</string>
<string name="select_input_method" msgid="3971267998568587025">"选择输入法"</string>
<string name="show_ime" msgid="6406112007347443383">"开启后,连接到实体键盘时,它会一直显示在屏幕上"</string>
- <string name="hardware" msgid="1800597768237606953">"显示虚拟键盘"</string>
+ <string name="hardware" msgid="3611039921284836033">"使用屏幕键盘"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"配置“<xliff:g id="DEVICE_NAME">%s</xliff:g>”"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"配置物理键盘"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"点按即可选择语言和布局"</string>
@@ -2316,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问手机的摄像头"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问平板电脑的摄像头"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"流式传输时无法访问此内容。您可以尝试在手机上访问。"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"在线播放时无法查看画中画"</string>
<string name="system_locale_title" msgid="711882686834677268">"系统默认设置"</string>
<string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"用于管理手表的配套手表个人资料权限"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index b4584bc..05558f67 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"拒絕"</string>
<string name="select_input_method" msgid="3971267998568587025">"選擇輸入法"</string>
<string name="show_ime" msgid="6406112007347443383">"在實體鍵盤處於連接狀態時保持顯示"</string>
- <string name="hardware" msgid="1800597768237606953">"顯示虛擬鍵盤"</string>
+ <string name="hardware" msgid="3611039921284836033">"使用屏幕鍵盤"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"設定「<xliff:g id="DEVICE_NAME">%s</xliff:g>」"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"設定實體鍵盤"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"輕按即可選取語言和鍵盤配置"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"無法使用應用程式"</string>
<string name="app_blocked_message" msgid="542972921087873023">"目前無法使用「<xliff:g id="APP_NAME">%1$s</xliff:g>」。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法使用「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"已抑制權限要求"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"無法使用相機"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"請繼續透過手機操作"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"無法使用麥克風"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用 Android TV 裝置存取。"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用平板電腦存取。"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取此應用程式,請改用手機存取。"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"此應用程式要求額外的權限,但串流工作階段期間無法授予權限。請先在 Android TV 裝置上授予權限。"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"此應用程式要求額外的權限,但串流工作階段期間無法授予權限。請先在平板電腦上授予權限。"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"此應用程式要求額外的權限,但串流工作階段期間無法授予權限。請先在手機上授予權限。"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"此應用程式要求額外的安全措施,請改用 Android TV 裝置。"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"此應用程式要求額外的安全措施,請改用平板電腦。"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"此應用程式要求額外的安全措施,請改用手機。"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取手機的相機"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取平板電腦的相機"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"串流播放時無法使用,請改用手機。"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"串流期間無法查看畫中畫"</string>
<string name="system_locale_title" msgid="711882686834677268">"系統預設"</string>
<string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"用於管理手錶的隨附手錶設定檔權限"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index dd4a484..f3a3203 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1395,8 +1395,8 @@
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"分享"</string>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"拒絕"</string>
<string name="select_input_method" msgid="3971267998568587025">"選擇輸入法"</string>
- <string name="show_ime" msgid="6406112007347443383">"使用實體鍵盤時仍繼續顯示虛擬鍵盤"</string>
- <string name="hardware" msgid="1800597768237606953">"顯示虛擬鍵盤"</string>
+ <string name="show_ime" msgid="6406112007347443383">"使用實體鍵盤時仍繼續顯示螢幕小鍵盤"</string>
+ <string name="hardware" msgid="3611039921284836033">"使用螢幕小鍵盤"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"設定「<xliff:g id="DEVICE_NAME">%s</xliff:g>」"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"設定實體鍵盤"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"輕觸即可選取語言和版面配置"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"應用程式無法使用"</string>
<string name="app_blocked_message" msgid="542972921087873023">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」目前無法使用。"</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"無法存取「<xliff:g id="ACTIVITY">%1$s</xliff:g>」"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"權限要求遭拒"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"無法使用相機"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"請繼續在手機上操作"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"無法使用麥克風"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用 Android TV 裝置。"</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個項目,請改用平板電腦。"</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"目前無法在 <xliff:g id="DEVICE">%1$s</xliff:g> 上存取這個應用程式,請改用手機。"</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"這個應用程式要求額外權限,但串流期間無法授權。請先在 Android TV 裝置上授予權限。"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"這個應用程式要求額外權限,但串流期間無法授權。請先在平板電腦上授予權限。"</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"這個應用程式要求額外權限,但串流期間無法授權。請先在手機上授予權限。"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"這個應用程式要求進行額外的安全性驗證,請改用 Android TV 裝置。"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"這個應用程式要求進行額外的安全性驗證,請改用平板電腦。"</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"這個應用程式要求進行額外的安全性驗證,請改用手機。"</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取手機的相機"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取平板電腦的相機"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"串流播放時無法存取這項內容,請改用手機。"</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"串流播放時無法查看子母畫面"</string>
<string name="system_locale_title" msgid="711882686834677268">"系統預設"</string>
<string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"用於管理智慧手錶的配對智慧手錶設定檔權限"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 03a21de..1387032 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1396,7 +1396,7 @@
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"YENQABA"</string>
<string name="select_input_method" msgid="3971267998568587025">"Khetha indlela yokufaka"</string>
<string name="show_ime" msgid="6406112007347443383">"Yigcine kusikrini ngenkathi kusebenza ikhibhodi ephathekayo"</string>
- <string name="hardware" msgid="1800597768237606953">"Bonisa ikhibhodi ebonakalayo"</string>
+ <string name="hardware" msgid="3611039921284836033">"Sebenzisa ikhibhodi ekuskrini"</string>
<string name="select_keyboard_layout_notification_title" msgid="5823199895322205589">"Lungisa i-<xliff:g id="DEVICE_NAME">%s</xliff:g>"</string>
<string name="select_multiple_keyboards_layout_notification_title" msgid="6999491025126641938">"Lungiselela amakhibhodi aphathekayo"</string>
<string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Thepha ukuze ukhethe ulimi nesakhiwo"</string>
@@ -1959,8 +1959,7 @@
<string name="app_blocked_title" msgid="7353262160455028160">"Uhlelo lokusebenza alutholakali"</string>
<string name="app_blocked_message" msgid="542972921087873023">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayitholakali khona manje."</string>
<string name="app_streaming_blocked_title" msgid="6090945835898766139">"okungatholakali <xliff:g id="ACTIVITY">%1$s</xliff:g>"</string>
- <!-- no translation found for app_streaming_blocked_title_for_permission_dialog (3805704317624448487) -->
- <skip />
+ <string name="app_streaming_blocked_title_for_permission_dialog" msgid="3805704317624448487">"Isicelo semvume sicindezelwe"</string>
<string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Ikhamera ayitholakali"</string>
<string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Qhubeka kufoni"</string>
<string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Imakrofoni ayitholakali"</string>
@@ -1971,12 +1970,9 @@
<string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama kudivayisi yakho ye-Android TV kunalokho."</string>
<string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama kuthebhulethi yakho kunalokho."</string>
<string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Lokhu akukwazi ukufinyelelwa ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho ngalesi sikhathi. Zama efonini yakho kunalokho."</string>
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (4706276040125072077) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (1824604581465771629) -->
- <skip />
- <!-- no translation found for app_streaming_blocked_message_for_permission_request (7755223160363292105) -->
- <skip />
+ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Le-app icela izimvume ezengeziwe, kodwa izimvume azikwazi ukunikezwa ngesikhathi sokusakaza-bukhoma. Nikeza imvume kudivayisi yakho ye-Android TV kuqala."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Le-app icela izimvume ezengeziwe, kodwa izimvume azikwazi ukunikezwa ngesikhathi sokusakaza-bukhoma. Nikeza imvume kuthebulethi yakho kuqala."</string>
+ <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Le-app icela izimvume ezengeziwe, kodwa izimvume azikwazi ukunikezwa ngesikhathi sokusakaza-bukhoma. Nikeza imvume kufoni yakho kuqala."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Le app icela ukuvikeleka okwengeziwe. Zama kudivayisi yakho ye-Android TV kunalokho."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Le app icela ukuvikeleka okwengeziwe. Zama kuthebhulethi yakho kunalokho."</string>
<string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Le app icela ukuvikeleka okwengeziwe. Zama efonini yakho kunalokho."</string>
@@ -2320,7 +2316,6 @@
<string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ayikwazi ukufinyelela ikhamera yefoni kusuka ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string>
<string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ayikwazi ukufinyelela ikhamera yethebulethi kusuka ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string>
<string name="vdm_secure_window" msgid="161700398158812314">"Lokhu akukwazi ukufinyelelwa ngenkathi usakaza. Zama efonini yakho kunalokho."</string>
- <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ayikwazi ukubuka isithombe esiphakathi kwesithombe ngenkathi isakaza"</string>
<string name="system_locale_title" msgid="711882686834677268">"Okuzenzakalelayo kwesistimu"</string>
<string name="default_card_name" msgid="9198284935962911468">"IKHADI <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
<string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Imvume yephrofayela ye-Companion Watch yokuphatha amawashi"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 44e3640..3b36c7a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1028,7 +1028,7 @@
requires swapping ROTATION_90 and ROTATION_270.
TODO(b/265991392): This should eventually be configured and parsed in
display_settings.xml -->
- <bool name="config_matchSecondaryInternalDisplaysOrientationToReverseDefaultDisplay">true</bool>
+ <bool name="config_matchSecondaryInternalDisplaysOrientationToReverseDefaultDisplay">false</bool>
<!-- Indicate available ColorDisplayManager.COLOR_MODE_xxx. -->
<integer-array name="config_availableColorModes">
@@ -2309,6 +2309,8 @@
<string name="config_systemFinancedDeviceController" translatable="false">com.android.devicelockcontroller</string>
<!-- The name of the package that will hold the call streaming role. -->
<string name="config_systemCallStreaming" translatable="false"></string>
+ <!-- The name of the package that will hold the default retail demo role. -->
+ <string name="config_defaultRetailDemo" translatable="false"></string>
<!-- The component name of the wear service class that will be started by the system server. -->
<string name="config_wearServiceComponent" translatable="false"></string>
@@ -5591,13 +5593,13 @@
<!-- Blur radius for the Option 3 in R.integer.config_letterboxBackgroundType. Values < 0 are
ignored and 0 is used. -->
- <dimen name="config_letterboxBackgroundWallpaperBlurRadius">31dp</dimen>
+ <dimen name="config_letterboxBackgroundWallpaperBlurRadius">24dp</dimen>
<!-- Alpha of a black translucent scrim showed over wallpaper letterbox background when
the Option 3 is selected for R.integer.config_letterboxBackgroundType.
Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead. -->
<item name="config_letterboxBackgroundWallaperDarkScrimAlpha" format="float" type="dimen">
- 0.5
+ 0.68
</item>
<!-- Corners appearance of the letterbox background.
@@ -5622,7 +5624,7 @@
but isn't supported on the device or both dark scrim alpha and blur radius aren't
provided.
-->
- <color name="config_letterboxBackgroundColor">@color/letterbox_background</color>
+ <color name="config_letterboxBackgroundColor">@color/system_on_secondary_fixed</color>
<!-- Horizontal position of a center of the letterboxed app window.
0 corresponds to the left side of the screen and 1 to the right side. If given value < 0
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 7b1e0a4..0f2c264a 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -95,8 +95,10 @@
<dimen name="navigation_bar_height_landscape_car_mode">96dp</dimen>
<!-- Width of the navigation bar when it is placed vertically on the screen in car mode -->
<dimen name="navigation_bar_width_car_mode">96dp</dimen>
- <!-- Height of notification icons in the status bar -->
+ <!-- Original dp height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">22dip</dimen>
+ <!-- New sp height of notification icons in the status bar -->
+ <dimen name="status_bar_icon_size_sp">22sp</dimen>
<!-- Desired size of system icons in status bar. -->
<dimen name="status_bar_system_icon_size">15dp</dimen>
<!-- Intrinsic size of most system icons in status bar. This is the default value that
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 49a1940..adc7fe0 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -119,6 +119,8 @@
</staging-public-group>
<staging-public-group type="string" first-id="0x01ba0000">
+ <!-- @hide @SystemApi -->
+ <public name="config_defaultRetailDemo" />
</staging-public-group>
<staging-public-group type="dimen" first-id="0x01b90000">
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 79964b3..164f713 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1560,4 +1560,8 @@
<style name="NotificationTombstoneAction" parent="NotificationAction">
<item name="textColor">#555555</item>
</style>
+
+ <!-- The default style for input method switch dialog -->
+ <style name="InputMethodSwitchDialogStyle" parent="AlertDialog.DeviceDefault">
+ </style>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a18d2c5..8d0ae19 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2306,6 +2306,7 @@
<java-symbol type="bool" name="config_alwaysUseCdmaRssi" />
<java-symbol type="dimen" name="status_bar_icon_size" />
+ <java-symbol type="dimen" name="status_bar_icon_size_sp" />
<java-symbol type="dimen" name="status_bar_system_icon_size" />
<java-symbol type="dimen" name="status_bar_system_icon_intrinsic_size" />
<java-symbol type="drawable" name="list_selector_pressed_holo_dark" />
@@ -4972,7 +4973,6 @@
<!-- For VirtualDeviceManager -->
<java-symbol type="string" name="vdm_camera_access_denied" />
<java-symbol type="string" name="vdm_secure_window" />
- <java-symbol type="string" name="vdm_pip_blocked" />
<java-symbol type="color" name="camera_privacy_light_day"/>
<java-symbol type="color" name="camera_privacy_light_night"/>
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
index 0525443..0c07470 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetActivityTest.java
@@ -24,6 +24,7 @@
import android.util.Property;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import androidx.test.rule.ActivityTestRule;
@@ -36,6 +37,8 @@
import org.junit.Test;
import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
@SmallTest
public class AnimatorSetActivityTest {
@@ -613,6 +616,68 @@
});
}
+ @Test
+ public void initAfterStartNotification() throws Throwable {
+ Property<int[], Integer> property = new Property<>(Integer.class, "firstValue") {
+ @Override
+ public Integer get(int[] target) {
+ throw new IllegalStateException("Shouldn't be called");
+ }
+
+ @Override
+ public void set(int[] target, Integer value) {
+ target[0] = value;
+ }
+ };
+ int[] target = new int[1];
+ ObjectAnimator animator1 = ObjectAnimator.ofInt(target, property, 0, 100);
+ ObjectAnimator animator2 = ObjectAnimator.ofInt(target, property, 0, 100);
+ ObjectAnimator animator3 = ObjectAnimator.ofInt(target, property, 0, 100);
+ animator1.setDuration(10);
+ animator2.setDuration(10);
+ animator3.setDuration(10);
+ AnimatorSet set = new AnimatorSet();
+ set.playSequentially(animator1, animator2, animator3);
+ final int[] values = new int[4];
+ animator2.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
+ values[0] = target[0];
+ animator2.setIntValues(target[0], target[0] + 100);
+ }
+
+ @Override
+ public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
+ values[1] = target[0];
+ }
+ });
+ animator3.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
+ values[2] = target[0];
+ animator3.setIntValues(target[0], target[0] + 100);
+ }
+
+ @Override
+ public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
+ values[3] = target[0];
+ }
+ });
+ final CountDownLatch latch = new CountDownLatch(1);
+ set.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(@NonNull Animator animation, boolean isReverse) {
+ latch.countDown();
+ }
+ });
+ mActivityRule.runOnUiThread(() -> set.start());
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+ assertEquals(100, values[0]);
+ assertEquals(200, values[1]);
+ assertEquals(200, values[2]);
+ assertEquals(300, values[3]);
+ }
+
/**
* Check that the animator list contains exactly the given animators and nothing else.
*/
diff --git a/core/tests/coretests/src/android/app/KeyguardManagerTest.java b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
index 958906c..ed8b288 100644
--- a/core/tests/coretests/src/android/app/KeyguardManagerTest.java
+++ b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
@@ -174,6 +174,22 @@
}
@Test
+ public void setLock_validatesCredential() {
+ // setLock() should validate the credential before setting it. Test one example, which is
+ // that PINs must contain only ASCII digits 0-9, i.e. bytes 48-57. Using bytes 0-9 is
+ // incorrect and should *not* be accepted.
+ byte[] invalidPin = new byte[] { 1, 2, 3, 4 };
+ byte[] validPin = "1234".getBytes();
+
+ assertFalse(mKeyguardManager.setLock(KeyguardManager.PIN, invalidPin, -1, null));
+ assertFalse(mKeyguardManager.isDeviceSecure());
+
+ assertTrue(mKeyguardManager.setLock(KeyguardManager.PIN, validPin, -1, null));
+ assertTrue(mKeyguardManager.isDeviceSecure());
+ assertTrue(mKeyguardManager.setLock(-1, null, KeyguardManager.PIN, validPin));
+ }
+
+ @Test
public void checkLock_correctCredentials() {
// Set to `true` to behave as if SET_INITIAL_LOCK permission had been granted.
doReturn(true).when(mKeyguardManager).checkInitialLockMethodUsage();
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 1516a07..a936cea 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -271,6 +271,54 @@
}
@Test
+ public void allPendingIntents_resilientToAnotherNotificationInExtras() {
+ PendingIntent contentIntent = createPendingIntent("content");
+ PendingIntent actionIntent = createPendingIntent("action");
+ Notification another = new Notification.Builder(mContext, "channel").build();
+ Bundle bundleContainingAnotherNotification = new Bundle();
+ bundleContainingAnotherNotification.putParcelable(null, another);
+ Notification source = new Notification.Builder(mContext, "channel")
+ .setContentIntent(contentIntent)
+ .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
+ .setExtras(bundleContainingAnotherNotification)
+ .build();
+
+ Parcel p = Parcel.obtain();
+ source.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ Notification unparceled = new Notification(p);
+
+ assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent);
+ }
+
+ @Test
+ public void allPendingIntents_alsoInPublicVersion() {
+ PendingIntent contentIntent = createPendingIntent("content");
+ PendingIntent actionIntent = createPendingIntent("action");
+ PendingIntent publicContentIntent = createPendingIntent("publicContent");
+ PendingIntent publicActionIntent = createPendingIntent("publicAction");
+ Notification source = new Notification.Builder(mContext, "channel")
+ .setContentIntent(contentIntent)
+ .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
+ .setPublicVersion(new Notification.Builder(mContext, "channel")
+ .setContentIntent(publicContentIntent)
+ .addAction(new Notification.Action.Builder(
+ null, "publicAction", publicActionIntent).build())
+ .build())
+ .build();
+
+ Parcel p = Parcel.obtain();
+ source.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ Notification unparceled = new Notification(p);
+
+ assertThat(unparceled.allPendingIntents).containsExactly(contentIntent, actionIntent,
+ publicContentIntent, publicActionIntent);
+ assertThat(unparceled.publicVersion.allPendingIntents).containsExactly(publicContentIntent,
+ publicActionIntent);
+ }
+
+ @Test
public void messagingStyle_isGroupConversation() {
mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle("self name")
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index 84c5400..33e81c1 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -42,6 +42,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.PasswordValidationError;
@@ -96,8 +97,7 @@
@Test
public void testComputeForPassword_metrics() {
- final PasswordMetrics metrics = PasswordMetrics.computeForPasswordOrPin(
- "6B~0z1Z3*8A".getBytes(), /* isPin */ false);
+ final PasswordMetrics metrics = metricsForPassword("6B~0z1Z3*8A");
assertEquals(11, metrics.length);
assertEquals(4, metrics.letters);
assertEquals(3, metrics.upperCase);
@@ -135,72 +135,54 @@
@Test
public void testDetermineComplexity_lowNumeric() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("1234".getBytes(),
- /* isPin */true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPin("1234").determineComplexity());
}
@Test
public void testDetermineComplexity_lowNumericComplex() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("124".getBytes(),
- /* isPin */ true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPin("124").determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphabetic() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("a!".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPassword("a!").determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphanumeric() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("a!1".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPassword("a!1").determineComplexity());
}
@Test
public void testDetermineComplexity_mediumNumericComplex() {
- assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPasswordOrPin("1238".getBytes(),
- /* isPin */ true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metricsForPin("1238").determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphabetic() {
- assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPasswordOrPin("ab!c".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metricsForPassword("ab!c").determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphanumeric() {
- assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPasswordOrPin("ab!1".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metricsForPassword("ab!1").determineComplexity());
}
@Test
public void testDetermineComplexity_highNumericComplex() {
- assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPasswordOrPin("12389647!".getBytes(),
- /* isPin */ true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_HIGH, metricsForPin("12389647!").determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPasswordOrPin("alphabetic!".getBytes(),
- /* isPin */ false).determineComplexity());
+ metricsForPassword("alphabetic!").determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPasswordOrPin("alphanumeric123!".getBytes(),
- /* isPin */ false).determineComplexity());
+ metricsForPassword("alphanumeric123!").determineComplexity());
}
@Test
@@ -419,6 +401,29 @@
PasswordValidationError.TOO_SHORT, 6);
}
+ private LockscreenCredential createPattern(String patternString) {
+ return LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(
+ patternString.getBytes()));
+ }
+
+ private static PasswordMetrics metricsForPassword(String password) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPassword(password));
+ }
+
+ private static PasswordMetrics metricsForPin(String pin) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPin(pin));
+ }
+
+ @Test
+ public void testValidateCredential_pattern() {
+ PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, createPattern("123")),
+ PasswordValidationError.TOO_SHORT, 4);
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, createPattern("1234")));
+ }
+
/**
* @param expected sequence of validation error codes followed by requirement values, must have
* even number of elements. Empty means no errors.
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java
index 944e2b0..59a1643 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteRawStatementTest.java
@@ -187,7 +187,7 @@
for (int i = 0; s.step() && i < 5; i++) {
boolean r = t.step();
assertTrue(r);
- assertEquals(t.getInt(0), s.getInt(0));
+ assertEquals(t.getColumnInt(0), s.getColumnInt(0));
found++;
}
assertFalse(t.step());
@@ -240,7 +240,7 @@
try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) {
boolean r = s.step();
assertTrue(r);
- int rows = s.getInt(0);
+ int rows = s.getColumnInt(0);
assertEquals(10, rows);
}
mDatabase.setTransactionSuccessful();
@@ -254,10 +254,10 @@
final String query = "SELECT i, d, t FROM t1 WHERE t = 'text03value'";
try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) {
assertTrue(s.step());
- assertEquals(3, s.getResultColumnsCount());
- int vi = s.getInt(0);
- double vd = s.getDouble(1);
- String vt = s.getText(2);
+ assertEquals(3, s.getResultColumnCount());
+ int vi = s.getColumnInt(0);
+ double vd = s.getColumnDouble(1);
+ String vt = s.getColumnText(2);
assertEquals(3 * 3, vi);
assertEquals(2.5 * 3, vd, 0.1);
assertEquals("text03value", vt);
@@ -273,10 +273,10 @@
final String query = "SELECT i, d, t FROM t1 WHERE i == 20";
try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) {
assertTrue(s.step());
- assertEquals(3, s.getResultColumnsCount());
- assertEquals(20, s.getInt(0));
- assertEquals(0.0, s.getDouble(1), 0.01);
- assertEquals(null, s.getText(2));
+ assertEquals(3, s.getResultColumnCount());
+ assertEquals(20, s.getColumnInt(0));
+ assertEquals(0.0, s.getColumnDouble(1), 0.01);
+ assertEquals(null, s.getColumnText(2));
// No more rows.
assertFalse(s.step());
}
@@ -383,7 +383,7 @@
// Verify that a statement cannot be accessed once closed.
try {
- s.getResultColumnsCount();
+ s.getResultColumnCount();
fail("accessed closed statement");
} catch (AssertionError e) {
// Pass on the fail from the try-block before the generic catch below can see it.
@@ -495,7 +495,7 @@
// Fetch the entire reference array.
s.bindInt(1, 1);
assertTrue(s.step());
- byte[] a = s.getBlob(0);
+ byte[] a = s.getColumnBlob(0);
assertTrue(Arrays.equals(src, a));
s.reset();
@@ -503,21 +503,21 @@
s.bindInt(1, 2);
assertTrue(s.step());
byte[] c = new byte[src.length];
- assertEquals(8, s.getBlob(0, c, 0, c.length, 0));
+ assertEquals(8, s.readColumnBlob(0, c, 0, c.length, 0));
assertTrue(Arrays.equals(src, 4, 4+8, c, 0, 0+8));
s.reset();
// Fetch the null.
s.bindInt(1, 3);
assertTrue(s.step());
- assertEquals(null, s.getBlob(0));
+ assertEquals(null, s.getColumnBlob(0));
s.reset();
// Fetch the null and ensure the buffer is not modified.
for (int i = 0; i < c.length; i++) c[i] = 0;
s.bindInt(1, 3);
assertTrue(s.step());
- assertEquals(0, s.getBlob(0, c, 0, c.length, 0));
+ assertEquals(0, s.readColumnBlob(0, c, 0, c.length, 0));
for (int i = 0; i < c.length; i++) assertEquals(0, c[i]);
s.reset();
}
@@ -553,17 +553,17 @@
mDatabase.beginTransaction();
try {
try (SQLiteRawStatement s = mDatabase.createRawStatement(sql)) {
- assertEquals(3, s.bindParameterCount());
+ assertEquals(3, s.getParameterCount());
- assertEquals(1, s.bindParameterIndex(":1"));
- assertEquals(2, s.bindParameterIndex("?2"));
- assertEquals(3, s.bindParameterIndex("@FOO"));
- assertEquals(0, s.bindParameterIndex("@BAR"));
+ assertEquals(1, s.getParameterIndex(":1"));
+ assertEquals(2, s.getParameterIndex("?2"));
+ assertEquals(3, s.getParameterIndex("@FOO"));
+ assertEquals(0, s.getParameterIndex("@BAR"));
- assertEquals(":1", s.bindParameterName(1));
- assertEquals("?2", s.bindParameterName(2));
- assertEquals("@FOO", s.bindParameterName(3));
- assertEquals(null, s.bindParameterName(4));
+ assertEquals(":1", s.getParameterName(1));
+ assertEquals("?2", s.getParameterName(2));
+ assertEquals("@FOO", s.getParameterName(3));
+ assertEquals(null, s.getParameterName(4));
}
} finally {
mDatabase.endTransaction();
@@ -574,7 +574,7 @@
try {
try (SQLiteRawStatement s = mDatabase.createRawStatement(sql)) {
// Error case. The name is not supposed to be null.
- assertEquals(0, s.bindParameterIndex(null));
+ assertEquals(0, s.getParameterIndex(null));
fail("expected a NullPointerException");
}
} catch (NullPointerException e) {
@@ -631,7 +631,7 @@
int found = 0;
try (var s = mDatabase.createRawStatement(query)) {
for (int i = 0; s.step(); i++) {
- int vi = s.getInt(0);
+ int vi = s.getColumnInt(0);
int expected = i * 3;
assertEquals(expected, vi);
found = i;
@@ -705,7 +705,7 @@
for (int i = 0; i < loops; i++) {
try (var s = mDatabase.createRawStatement(query)) {
assertTrue(s.step());
- int vi = s.getInt(0);
+ int vi = s.getColumnInt(0);
int expected = 0;
assertEquals(expected, vi);
}
@@ -775,7 +775,7 @@
for (int i = 0; i < size; i++) {
assertTrue(s.step());
for (int j = 0; j < 12; j++) {
- assertEquals(s.getInt(j), wideVal(i, j));
+ assertEquals(s.getColumnInt(j), wideVal(i, j));
}
}
}
@@ -820,7 +820,7 @@
long start = SystemClock.uptimeMillis();
try (SQLiteRawStatement s = mDatabase.createRawStatement(query)) {
while (s.step()) {
- s.getInt(0);
+ s.getColumnInt(0);
}
}
long elapsed = SystemClock.uptimeMillis() - start;
@@ -866,7 +866,7 @@
// No row is returned by this query.
assertFalse(r);
s.reset();
- assertEquals(i + 1, mDatabase.lastInsertRowId());
+ assertEquals(i + 1, mDatabase.getLastInsertRowId());
}
}
mDatabase.setTransactionSuccessful();
@@ -889,7 +889,7 @@
// No row is returned by this query.
assertFalse(r);
s.reset();
- assertEquals(size + i + 1, mDatabase.lastInsertRowId());
+ assertEquals(size + i + 1, mDatabase.getLastInsertRowId());
}
}
mDatabase.setTransactionSuccessful();
@@ -920,12 +920,12 @@
mDatabase.beginTransactionReadOnly();
try (SQLiteRawStatement s = mDatabase.createRawStatement(sql)) {
- assertEquals(1, s.bindParameterIndex(head));
- assertEquals(head, s.bindParameterName(1));
+ assertEquals(1, s.getParameterIndex(head));
+ assertEquals(head, s.getParameterName(1));
s.bindInt(1, 20);
assertTrue(s.step());
- assertEquals(2, s.getInt(0));
- assertEquals(cat, s.getName(0));
+ assertEquals(2, s.getColumnInt(0));
+ assertEquals(cat, s.getColumnName(0));
} finally {
mDatabase.endTransaction();
}
diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java
index 1a8dd99..1da724a 100644
--- a/core/tests/coretests/src/android/view/ViewAttachTest.java
+++ b/core/tests/coretests/src/android/view/ViewAttachTest.java
@@ -92,4 +92,43 @@
assertFalse(shouldDrawRoundScrollbars);
}
}
+
+ /**
+ * Make sure that on any attached view, if the view is full-screen and hosted
+ * on a round device, the round scrollbars will be displayed even if the activity
+ * window is offset.
+ *
+ * @throws Throwable
+ */
+ @UiThreadTest
+ public void testRoundScrollbarsWithMargins() throws Throwable {
+ final ViewAttachTestActivity activity = getActivity();
+ final View rootView = activity.getWindow().getDecorView();
+ final WindowManager.LayoutParams params =
+ new WindowManager.LayoutParams(
+ rootView.getWidth(),
+ rootView.getHeight(),
+ 50, /* xPosition */
+ 0, /* yPosition */
+ WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ PixelFormat.TRANSLUCENT);
+
+ rootView.setLayoutParams(params);
+
+ // Configure margins to make sure they don't cause issues configuring rounded scrollbars.
+ final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(1, 1);
+ lp.setMargins(1, 2, 3, 4);
+ rootView.setLayoutParams(lp);
+
+ View contentView = activity.findViewById(R.id.view_attach_view);
+ boolean shouldDrawRoundScrollbars = contentView.shouldDrawRoundScrollbar();
+
+ if (activity.getResources().getConfiguration().isScreenRound()) {
+ assertTrue(shouldDrawRoundScrollbars);
+ } else {
+ // Never draw round scrollbars on non-round devices.
+ assertFalse(shouldDrawRoundScrollbars);
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/content/PackageMonitorTest.java b/core/tests/coretests/src/com/android/internal/content/PackageMonitorTest.java
index 5290478..7ccbf1d 100644
--- a/core/tests/coretests/src/com/android/internal/content/PackageMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/PackageMonitorTest.java
@@ -63,23 +63,20 @@
public void testPackageMonitorMultipleRegisterThrowsException() throws Exception {
PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor());
- spyPackageMonitor.register(mMockContext, UserHandle.ALL, false /* externalStorage */,
- mMockHandler);
+ spyPackageMonitor.register(mMockContext, UserHandle.ALL, mMockHandler);
assertThat(spyPackageMonitor.getRegisteredHandler()).isEqualTo(mMockHandler);
verify(mMockContext, times(2)).registerReceiverAsUser(any(), eq(UserHandle.ALL), any(),
eq(null), eq(mMockHandler));
assertThrows(IllegalStateException.class,
- () -> spyPackageMonitor.register(mMockContext, UserHandle.ALL,
- false /* externalStorage */, mMockHandler));
+ () -> spyPackageMonitor.register(mMockContext, UserHandle.ALL, mMockHandler));
}
@Test
public void testPackageMonitorRegisterMultipleUnRegisterThrowsException() throws Exception {
PackageMonitor spyPackageMonitor = spy(new TestPackageMonitor());
- spyPackageMonitor.register(mMockContext, UserHandle.ALL, false /* externalStorage */,
- mMockHandler);
+ spyPackageMonitor.register(mMockContext, UserHandle.ALL, mMockHandler);
spyPackageMonitor.unregister();
assertThrows(IllegalStateException.class, spyPackageMonitor::unregister);
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 8f83461..b61f995 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -79,6 +79,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -93,6 +94,8 @@
private static final String ENUM_NAME_PREFIX =
"UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__";
+ private static final ArrayList<String> DEPRECATED_VALUES = new ArrayList<>();
+
private ViewAttachTestActivity mActivity;
private View mView;
private HandlerThread mWorker;
@@ -126,6 +129,7 @@
CUJ_NOTIFICATION_SHADE_ROW_SWIPE, getEnumName("SHADE_ROW_SWIPE"));
ENUM_NAME_EXCEPTION_MAP.put(
CUJ_NOTIFICATION_SHADE_SCROLL_FLING, getEnumName("SHADE_SCROLL_FLING"));
+ DEPRECATED_VALUES.add(ENUM_NAME_PREFIX + "IME_INSETS_ANIMATION");
}
private static String getEnumName(String name) {
@@ -239,6 +243,7 @@
Map<Integer, String> enumsMap = Arrays.stream(FrameworkStatsLog.class.getDeclaredFields())
.filter(f -> f.getName().startsWith(ENUM_NAME_PREFIX)
+ && !DEPRECATED_VALUES.contains(f.getName())
&& Modifier.isStatic(f.getModifiers())
&& f.getType() == int.class)
.collect(Collectors.toMap(this::getIntFieldChecked, Field::getName));
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
index 12abaa9..5692742 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
@@ -158,6 +158,16 @@
}
@Test
+ public void testPinWithInvalidChars() {
+ LockscreenCredential pin = LockscreenCredential.createPin("\n\n\n\n");
+ assertTrue(pin.hasInvalidChars());
+ try {
+ pin.validateBasicRequirements();
+ fail("should not be able to set PIN with invalid chars");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @Test
public void testSanitize() {
LockscreenCredential password = LockscreenCredential.createPassword("password");
password.zeroize();
diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp
index f90a74d..3dd9ba9 100644
--- a/data/fonts/Android.bp
+++ b/data/fonts/Android.bp
@@ -52,3 +52,8 @@
name: "fonts.xml",
src: "fonts.xml",
}
+
+prebuilt_etc {
+ name: "font_fallback.xml",
+ src: "font_fallback.xml",
+}
diff --git a/data/fonts/font_fallback.xml b/data/fonts/font_fallback.xml
new file mode 100644
index 0000000..1e97fce
--- /dev/null
+++ b/data/fonts/font_fallback.xml
@@ -0,0 +1,1630 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ In this file, all fonts without names are added to the default list.
+ Fonts are chosen based on a match: full BCP-47 language tag including
+ script, then just language, and finally order (the first font containing
+ the glyph).
+
+ Order of appearance is also the tiebreaker for weight matching. This is
+ the reason why the 900 weights of Roboto precede the 700 weights - we
+ prefer the former when an 800 weight is requested. Since bold spans
+ effectively add 300 to the weight, this ensures that 900 is the bold
+ paired with the 500 weight, ensuring adequate contrast.
+
+ TODO(rsheeter) update comment; ordering to match 800 to 900 is no longer required
+-->
+<familyset version="23">
+ <!-- first font is default -->
+ <family name="sans-serif">
+ <font weight="100" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ <font weight="100" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ </family>
+
+
+ <!-- Note that aliases must come after the fonts they reference. -->
+ <alias name="sans-serif-thin" to="sans-serif" weight="100" />
+ <alias name="sans-serif-light" to="sans-serif" weight="300" />
+ <alias name="sans-serif-medium" to="sans-serif" weight="500" />
+ <alias name="sans-serif-black" to="sans-serif" weight="900" />
+ <alias name="arial" to="sans-serif" />
+ <alias name="helvetica" to="sans-serif" />
+ <alias name="tahoma" to="sans-serif" />
+ <alias name="verdana" to="sans-serif" />
+
+ <family name="sans-serif-condensed">
+ <font weight="100" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="normal">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="0" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ <font weight="100" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="italic">Roboto-Regular.ttf
+ <axis tag="ital" stylevalue="1" />
+ <axis tag="wdth" stylevalue="75" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ </family>
+ <alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" />
+ <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" />
+
+ <family name="serif">
+ <font weight="400" style="normal" postScriptName="NotoSerif">NotoSerif-Regular.ttf</font>
+ <font weight="700" style="normal">NotoSerif-Bold.ttf</font>
+ <font weight="400" style="italic">NotoSerif-Italic.ttf</font>
+ <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font>
+ </family>
+ <alias name="serif-bold" to="serif" weight="700" />
+ <alias name="times" to="serif" />
+ <alias name="times new roman" to="serif" />
+ <alias name="palatino" to="serif" />
+ <alias name="georgia" to="serif" />
+ <alias name="baskerville" to="serif" />
+ <alias name="goudy" to="serif" />
+ <alias name="fantasy" to="serif" />
+ <alias name="ITC Stone Serif" to="serif" />
+
+ <family name="monospace">
+ <font weight="400" style="normal">DroidSansMono.ttf</font>
+ </family>
+ <alias name="sans-serif-monospace" to="monospace" />
+ <alias name="monaco" to="monospace" />
+
+ <family name="serif-monospace">
+ <font weight="400" style="normal" postScriptName="CutiveMono-Regular">CutiveMono.ttf</font>
+ </family>
+ <alias name="courier" to="serif-monospace" />
+ <alias name="courier new" to="serif-monospace" />
+
+ <family name="casual">
+ <font weight="400" style="normal" postScriptName="ComingSoon-Regular">ComingSoon.ttf</font>
+ </family>
+
+ <family name="cursive">
+ <font weight="400" style="normal">DancingScript-Regular.ttf
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="700" style="normal">DancingScript-Regular.ttf
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ </family>
+
+ <family name="sans-serif-smallcaps">
+ <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
+ </family>
+
+ <family name="source-sans-pro">
+ <font weight="400" style="normal">SourceSansPro-Regular.ttf</font>
+ <font weight="400" style="italic">SourceSansPro-Italic.ttf</font>
+ <font weight="600" style="normal">SourceSansPro-SemiBold.ttf</font>
+ <font weight="600" style="italic">SourceSansPro-SemiBoldItalic.ttf</font>
+ <font weight="700" style="normal">SourceSansPro-Bold.ttf</font>
+ <font weight="700" style="italic">SourceSansPro-BoldItalic.ttf</font>
+ </family>
+ <alias name="source-sans-pro-semi-bold" to="source-sans-pro" weight="600"/>
+
+ <family name="roboto-flex">
+ <font weight="100" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="normal">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="0" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ <font weight="100" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="100" />
+ </font>
+ <font weight="200" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="200" />
+ </font>
+ <font weight="300" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="300" />
+ </font>
+ <font weight="400" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="400" />
+ </font>
+ <font weight="500" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="500" />
+ </font>
+ <font weight="600" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="600" />
+ </font>
+ <font weight="700" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="700" />
+ </font>
+ <font weight="800" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="800" />
+ </font>
+ <font weight="900" style="italic">RobotoFlex-Regular.ttf
+ <axis tag="slnt" stylevalue="-10" />
+ <axis tag="wdth" stylevalue="100" />
+ <axis tag="wght" stylevalue="900" />
+ </font>
+ </family>
+
+ <!-- fallback fonts -->
+ <family lang="und-Arab" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoNaskhArabic">
+ NotoNaskhArabic-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
+ </family>
+ <family lang="und-Arab" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoNaskhArabicUI">
+ NotoNaskhArabicUI-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
+ </family>
+ <family lang="und-Ethi">
+ <font weight="400" style="normal" postScriptName="NotoSansEthiopic-Regular">
+ NotoSansEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansEthiopic-Regular">
+ NotoSansEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansEthiopic-Regular">
+ NotoSansEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansEthiopic-Regular">
+ NotoSansEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifEthiopic-Regular">NotoSerifEthiopic-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Hebr">
+ <font weight="400" style="normal" postScriptName="NotoSansHebrew">
+ NotoSansHebrew-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font>
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font>
+ </family>
+ <family lang="und-Thai" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansThai">NotoSansThai-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
+ <font weight="400" style="normal" fallbackFor="serif">
+ NotoSerifThai-Regular.ttf
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font>
+ </family>
+ <family lang="und-Thai" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansThaiUI">
+ NotoSansThaiUI-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
+ </family>
+ <family lang="und-Armn">
+ <font weight="400" style="normal" postScriptName="NotoSansArmenian-Regular">
+ NotoSansArmenian-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansArmenian-Regular">
+ NotoSansArmenian-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansArmenian-Regular">
+ NotoSansArmenian-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansArmenian-Regular">
+ NotoSansArmenian-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifArmenian-Regular">NotoSerifArmenian-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Geor,und-Geok">
+ <font weight="400" style="normal" postScriptName="NotoSansGeorgian-Regular">
+ NotoSansGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansGeorgian-Regular">
+ NotoSansGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansGeorgian-Regular">
+ NotoSansGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansGeorgian-Regular">
+ NotoSansGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGeorgian-Regular">NotoSerifGeorgian-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Deva" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansDevanagari-Regular">
+ NotoSansDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansDevanagari-Regular">
+ NotoSansDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansDevanagari-Regular">
+ NotoSansDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansDevanagari-Regular">
+ NotoSansDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifDevanagari-Regular">NotoSerifDevanagari-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Deva" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
+ NotoSansDevanagariUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
+ NotoSansDevanagariUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
+ NotoSansDevanagariUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansDevanagariUI-Regular">
+ NotoSansDevanagariUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+
+ <!-- All scripts of India should come after Devanagari, due to shared
+ danda characters.
+ -->
+ <family lang="und-Gujr" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansGujarati">
+ NotoSansGujarati-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGujarati-Regular">NotoSerifGujarati-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Gujr" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansGujaratiUI">
+ NotoSansGujaratiUI-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
+ </family>
+ <family lang="und-Guru" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansGurmukhi-Regular">
+ NotoSansGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansGurmukhi-Regular">
+ NotoSansGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansGurmukhi-Regular">
+ NotoSansGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansGurmukhi-Regular">
+ NotoSansGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifGurmukhi-Regular">NotoSerifGurmukhi-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Guru" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
+ NotoSansGurmukhiUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
+ NotoSansGurmukhiUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
+ NotoSansGurmukhiUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansGurmukhiUI-Regular">
+ NotoSansGurmukhiUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Taml" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansTamil-Regular">
+ NotoSansTamil-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansTamil-Regular">
+ NotoSansTamil-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansTamil-Regular">
+ NotoSansTamil-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansTamil-Regular">
+ NotoSansTamil-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTamil-Regular">NotoSerifTamil-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Taml" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansTamilUI-Regular">
+ NotoSansTamilUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansTamilUI-Regular">
+ NotoSansTamilUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansTamilUI-Regular">
+ NotoSansTamilUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansTamilUI-Regular">
+ NotoSansTamilUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Mlym" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansMalayalam-Regular">
+ NotoSansMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansMalayalam-Regular">
+ NotoSansMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansMalayalam-Regular">
+ NotoSansMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansMalayalam-Regular">
+ NotoSansMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifMalayalam-Regular">NotoSerifMalayalam-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Mlym" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
+ NotoSansMalayalamUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
+ NotoSansMalayalamUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
+ NotoSansMalayalamUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansMalayalamUI-Regular">
+ NotoSansMalayalamUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Beng" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansBengali-Regular">
+ NotoSansBengali-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansBengali-Regular">
+ NotoSansBengali-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansBengali-Regular">
+ NotoSansBengali-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansBengali-Regular">
+ NotoSansBengali-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifBengali-Regular">NotoSerifBengali-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Beng" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansBengaliUI-Regular">
+ NotoSansBengaliUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansBengaliUI-Regular">
+ NotoSansBengaliUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansBengaliUI-Regular">
+ NotoSansBengaliUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansBengaliUI-Regular">
+ NotoSansBengaliUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Telu" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansTelugu-Regular">
+ NotoSansTelugu-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansTelugu-Regular">
+ NotoSansTelugu-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansTelugu-Regular">
+ NotoSansTelugu-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansTelugu-Regular">
+ NotoSansTelugu-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifTelugu-Regular">NotoSerifTelugu-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Telu" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansTeluguUI-Regular">
+ NotoSansTeluguUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansTeluguUI-Regular">
+ NotoSansTeluguUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansTeluguUI-Regular">
+ NotoSansTeluguUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansTeluguUI-Regular">
+ NotoSansTeluguUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Knda" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansKannada-Regular">
+ NotoSansKannada-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansKannada-Regular">
+ NotoSansKannada-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansKannada-Regular">
+ NotoSansKannada-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansKannada-Regular">
+ NotoSansKannada-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifKannada-Regular">NotoSerifKannada-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Knda" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansKannadaUI-Regular">
+ NotoSansKannadaUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansKannadaUI-Regular">
+ NotoSansKannadaUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansKannadaUI-Regular">
+ NotoSansKannadaUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansKannadaUI-Regular">
+ NotoSansKannadaUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Orya" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansOriya">NotoSansOriya-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
+ </family>
+ <family lang="und-Orya" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansOriyaUI">
+ NotoSansOriyaUI-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
+ </family>
+ <family lang="und-Sinh" variant="elegant">
+ <font weight="400" style="normal" postScriptName="NotoSansSinhala-Regular">
+ NotoSansSinhala-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansSinhala-Regular">
+ NotoSansSinhala-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansSinhala-Regular">
+ NotoSansSinhala-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansSinhala-Regular">
+ NotoSansSinhala-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif"
+ postScriptName="NotoSerifSinhala-Regular">NotoSerifSinhala-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Sinh" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
+ NotoSansSinhalaUI-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
+ NotoSansSinhalaUI-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
+ NotoSansSinhalaUI-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansSinhalaUI-Regular">
+ NotoSansSinhalaUI-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Khmr" variant="elegant">
+ <font weight="100" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="26.0"/>
+ </font>
+ <font weight="200" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="39.0"/>
+ </font>
+ <font weight="300" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="58.0"/>
+ </font>
+ <font weight="400" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="90.0"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="108.0"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="128.0"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="151.0"/>
+ </font>
+ <font weight="800" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="169.0"/>
+ </font>
+ <font weight="900" style="normal" postScriptName="NotoSansKhmer-Regular">
+ NotoSansKhmer-VF.ttf
+ <axis tag="wdth" stylevalue="100.0"/>
+ <axis tag="wght" stylevalue="190.0"/>
+ </font>
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifKhmer-Regular.otf</font>
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font>
+ </family>
+ <family lang="und-Khmr" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansKhmerUI">
+ NotoSansKhmerUI-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
+ </family>
+ <family lang="und-Laoo" variant="elegant">
+ <font weight="400" style="normal">NotoSansLao-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansLao-Bold.ttf</font>
+ <font weight="400" style="normal" fallbackFor="serif">
+ NotoSerifLao-Regular.ttf
+ </font>
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font>
+ </family>
+ <family lang="und-Laoo" variant="compact">
+ <font weight="400" style="normal" postScriptName="NotoSansLaoUI">NotoSansLaoUI-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
+ </family>
+ <family lang="und-Mymr" variant="elegant">
+ <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font>
+ <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font>
+ <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font>
+ <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font>
+ <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font>
+ </family>
+ <family lang="und-Mymr" variant="compact">
+ <font weight="400" style="normal">NotoSansMyanmarUI-Regular.otf</font>
+ <font weight="500" style="normal">NotoSansMyanmarUI-Medium.otf</font>
+ <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
+ </family>
+ <family lang="und-Thaa">
+ <font weight="400" style="normal" postScriptName="NotoSansThaana">
+ NotoSansThaana-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
+ </family>
+ <family lang="und-Cham">
+ <font weight="400" style="normal" postScriptName="NotoSansCham">NotoSansCham-Regular.ttf
+ </font>
+ <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
+ </family>
+ <family lang="und-Ahom">
+ <font weight="400" style="normal">NotoSansAhom-Regular.otf</font>
+ </family>
+ <family lang="und-Adlm">
+ <font weight="400" style="normal" postScriptName="NotoSansAdlam-Regular">
+ NotoSansAdlam-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansAdlam-Regular">
+ NotoSansAdlam-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansAdlam-Regular">
+ NotoSansAdlam-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansAdlam-Regular">
+ NotoSansAdlam-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Avst">
+ <font weight="400" style="normal" postScriptName="NotoSansAvestan">
+ NotoSansAvestan-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Bali">
+ <font weight="400" style="normal" postScriptName="NotoSansBalinese">
+ NotoSansBalinese-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Bamu">
+ <font weight="400" style="normal" postScriptName="NotoSansBamum">NotoSansBamum-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Batk">
+ <font weight="400" style="normal" postScriptName="NotoSansBatak">NotoSansBatak-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Brah">
+ <font weight="400" style="normal" postScriptName="NotoSansBrahmi">
+ NotoSansBrahmi-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Bugi">
+ <font weight="400" style="normal" postScriptName="NotoSansBuginese">
+ NotoSansBuginese-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Buhd">
+ <font weight="400" style="normal" postScriptName="NotoSansBuhid">NotoSansBuhid-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Cans">
+ <font weight="400" style="normal">
+ NotoSansCanadianAboriginal-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Cari">
+ <font weight="400" style="normal" postScriptName="NotoSansCarian">
+ NotoSansCarian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Cakm">
+ <font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
+ </family>
+ <family lang="und-Cher">
+ <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
+ </family>
+ <family lang="und-Copt">
+ <font weight="400" style="normal" postScriptName="NotoSansCoptic">
+ NotoSansCoptic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Xsux">
+ <font weight="400" style="normal" postScriptName="NotoSansCuneiform">
+ NotoSansCuneiform-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Cprt">
+ <font weight="400" style="normal" postScriptName="NotoSansCypriot">
+ NotoSansCypriot-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Dsrt">
+ <font weight="400" style="normal" postScriptName="NotoSansDeseret">
+ NotoSansDeseret-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Egyp">
+ <font weight="400" style="normal" postScriptName="NotoSansEgyptianHieroglyphs">
+ NotoSansEgyptianHieroglyphs-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Elba">
+ <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font>
+ </family>
+ <family lang="und-Glag">
+ <font weight="400" style="normal" postScriptName="NotoSansGlagolitic">
+ NotoSansGlagolitic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Goth">
+ <font weight="400" style="normal" postScriptName="NotoSansGothic">
+ NotoSansGothic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Hano">
+ <font weight="400" style="normal" postScriptName="NotoSansHanunoo">
+ NotoSansHanunoo-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Armi">
+ <font weight="400" style="normal" postScriptName="NotoSansImperialAramaic">
+ NotoSansImperialAramaic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Phli">
+ <font weight="400" style="normal" postScriptName="NotoSansInscriptionalPahlavi">
+ NotoSansInscriptionalPahlavi-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Prti">
+ <font weight="400" style="normal" postScriptName="NotoSansInscriptionalParthian">
+ NotoSansInscriptionalParthian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Java">
+ <font weight="400" style="normal">NotoSansJavanese-Regular.otf</font>
+ </family>
+ <family lang="und-Kthi">
+ <font weight="400" style="normal" postScriptName="NotoSansKaithi">
+ NotoSansKaithi-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Kali">
+ <font weight="400" style="normal" postScriptName="NotoSansKayahLi">
+ NotoSansKayahLi-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Khar">
+ <font weight="400" style="normal" postScriptName="NotoSansKharoshthi">
+ NotoSansKharoshthi-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Lepc">
+ <font weight="400" style="normal" postScriptName="NotoSansLepcha">
+ NotoSansLepcha-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Limb">
+ <font weight="400" style="normal" postScriptName="NotoSansLimbu">NotoSansLimbu-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Linb">
+ <font weight="400" style="normal" postScriptName="NotoSansLinearB">
+ NotoSansLinearB-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Lisu">
+ <font weight="400" style="normal" postScriptName="NotoSansLisu">NotoSansLisu-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Lyci">
+ <font weight="400" style="normal" postScriptName="NotoSansLycian">
+ NotoSansLycian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Lydi">
+ <font weight="400" style="normal" postScriptName="NotoSansLydian">
+ NotoSansLydian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Mand">
+ <font weight="400" style="normal" postScriptName="NotoSansMandaic">
+ NotoSansMandaic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Mtei">
+ <font weight="400" style="normal" postScriptName="NotoSansMeeteiMayek">
+ NotoSansMeeteiMayek-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Talu">
+ <font weight="400" style="normal" postScriptName="NotoSansNewTaiLue">
+ NotoSansNewTaiLue-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Nkoo">
+ <font weight="400" style="normal" postScriptName="NotoSansNKo">NotoSansNKo-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Ogam">
+ <font weight="400" style="normal" postScriptName="NotoSansOgham">NotoSansOgham-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Olck">
+ <font weight="400" style="normal" postScriptName="NotoSansOlChiki">
+ NotoSansOlChiki-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Ital">
+ <font weight="400" style="normal" postScriptName="NotoSansOldItalic">
+ NotoSansOldItalic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Xpeo">
+ <font weight="400" style="normal" postScriptName="NotoSansOldPersian">
+ NotoSansOldPersian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Sarb">
+ <font weight="400" style="normal" postScriptName="NotoSansOldSouthArabian">
+ NotoSansOldSouthArabian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Orkh">
+ <font weight="400" style="normal" postScriptName="NotoSansOldTurkic">
+ NotoSansOldTurkic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Osge">
+ <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
+ </family>
+ <family lang="und-Osma">
+ <font weight="400" style="normal" postScriptName="NotoSansOsmanya">
+ NotoSansOsmanya-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Phnx">
+ <font weight="400" style="normal" postScriptName="NotoSansPhoenician">
+ NotoSansPhoenician-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Rjng">
+ <font weight="400" style="normal" postScriptName="NotoSansRejang">
+ NotoSansRejang-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Runr">
+ <font weight="400" style="normal" postScriptName="NotoSansRunic">NotoSansRunic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Samr">
+ <font weight="400" style="normal" postScriptName="NotoSansSamaritan">
+ NotoSansSamaritan-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Saur">
+ <font weight="400" style="normal" postScriptName="NotoSansSaurashtra">
+ NotoSansSaurashtra-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Shaw">
+ <font weight="400" style="normal" postScriptName="NotoSansShavian">
+ NotoSansShavian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Sund">
+ <font weight="400" style="normal" postScriptName="NotoSansSundanese">
+ NotoSansSundanese-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Sylo">
+ <font weight="400" style="normal" postScriptName="NotoSansSylotiNagri">
+ NotoSansSylotiNagri-Regular.ttf
+ </font>
+ </family>
+ <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. -->
+ <family lang="und-Syre">
+ <font weight="400" style="normal" postScriptName="NotoSansSyriacEstrangela">
+ NotoSansSyriacEstrangela-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Syrn">
+ <font weight="400" style="normal" postScriptName="NotoSansSyriacEastern">
+ NotoSansSyriacEastern-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Syrj">
+ <font weight="400" style="normal" postScriptName="NotoSansSyriacWestern">
+ NotoSansSyriacWestern-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Tglg">
+ <font weight="400" style="normal" postScriptName="NotoSansTagalog">
+ NotoSansTagalog-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Tagb">
+ <font weight="400" style="normal" postScriptName="NotoSansTagbanwa">
+ NotoSansTagbanwa-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Lana">
+ <font weight="400" style="normal" postScriptName="NotoSansTaiTham">
+ NotoSansTaiTham-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Tavt">
+ <font weight="400" style="normal" postScriptName="NotoSansTaiViet">
+ NotoSansTaiViet-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Tibt">
+ <font weight="400" style="normal" postScriptName="NotoSerifTibetan-Regular">
+ NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSerifTibetan-Regular">
+ NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSerifTibetan-Regular">
+ NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSerifTibetan-Regular">
+ NotoSerifTibetan-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Tfng">
+ <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font>
+ </family>
+ <family lang="und-Ugar">
+ <font weight="400" style="normal" postScriptName="NotoSansUgaritic">
+ NotoSansUgaritic-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Vaii">
+ <font weight="400" style="normal" postScriptName="NotoSansVai">NotoSansVai-Regular.ttf
+ </font>
+ </family>
+ <family>
+ <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
+ </family>
+ <family lang="zh-Hans">
+ <font weight="400" style="normal" index="2" postScriptName="NotoSansCJKjp-Regular">
+ NotoSansCJK-Regular.ttc
+ </font>
+ <font weight="400" style="normal" index="2" fallbackFor="serif"
+ postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
+ </font>
+ </family>
+ <family lang="zh-Hant,zh-Bopo">
+ <font weight="400" style="normal" index="3" postScriptName="NotoSansCJKjp-Regular">
+ NotoSansCJK-Regular.ttc
+ </font>
+ <font weight="400" style="normal" index="3" fallbackFor="serif"
+ postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
+ </font>
+ </family>
+ <family lang="ja">
+ <font weight="400" style="normal" index="0" postScriptName="NotoSansCJKjp-Regular">
+ NotoSansCJK-Regular.ttc
+ </font>
+ <font weight="400" style="normal" index="0" fallbackFor="serif"
+ postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
+ </font>
+ </family>
+ <family lang="ko">
+ <font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
+ NotoSansCJK-Regular.ttc
+ </font>
+ <font weight="400" style="normal" index="1" fallbackFor="serif"
+ postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
+ </font>
+ </family>
+ <family lang="und-Zsye">
+ <font weight="400" style="normal">NotoColorEmoji.ttf</font>
+ </family>
+ <family lang="und-Zsye">
+ <font weight="400" style="normal">NotoColorEmojiFlags.ttf</font>
+ </family>
+ <family lang="und-Zsym">
+ <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
+ </family>
+ <!--
+ Tai Le, Yi, Mongolian, and Phags-pa are intentionally kept last, to make sure they don't
+ override the East Asian punctuation for Chinese.
+ -->
+ <family lang="und-Tale">
+ <font weight="400" style="normal" postScriptName="NotoSansTaiLe">NotoSansTaiLe-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Yiii">
+ <font weight="400" style="normal" postScriptName="NotoSansYi">NotoSansYi-Regular.ttf</font>
+ </family>
+ <family lang="und-Mong">
+ <font weight="400" style="normal" postScriptName="NotoSansMongolian">
+ NotoSansMongolian-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Phag">
+ <font weight="400" style="normal" postScriptName="NotoSansPhagsPa">
+ NotoSansPhagsPa-Regular.ttf
+ </font>
+ </family>
+ <family lang="und-Hluw">
+ <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font>
+ </family>
+ <family lang="und-Bass">
+ <font weight="400" style="normal">NotoSansBassaVah-Regular.otf</font>
+ </family>
+ <family lang="und-Bhks">
+ <font weight="400" style="normal">NotoSansBhaiksuki-Regular.otf</font>
+ </family>
+ <family lang="und-Hatr">
+ <font weight="400" style="normal">NotoSansHatran-Regular.otf</font>
+ </family>
+ <family lang="und-Lina">
+ <font weight="400" style="normal">NotoSansLinearA-Regular.otf</font>
+ </family>
+ <family lang="und-Mani">
+ <font weight="400" style="normal">NotoSansManichaean-Regular.otf</font>
+ </family>
+ <family lang="und-Marc">
+ <font weight="400" style="normal">NotoSansMarchen-Regular.otf</font>
+ </family>
+ <family lang="und-Merc">
+ <font weight="400" style="normal">NotoSansMeroitic-Regular.otf</font>
+ </family>
+ <family lang="und-Plrd">
+ <font weight="400" style="normal">NotoSansMiao-Regular.otf</font>
+ </family>
+ <family lang="und-Mroo">
+ <font weight="400" style="normal">NotoSansMro-Regular.otf</font>
+ </family>
+ <family lang="und-Mult">
+ <font weight="400" style="normal">NotoSansMultani-Regular.otf</font>
+ </family>
+ <family lang="und-Nbat">
+ <font weight="400" style="normal">NotoSansNabataean-Regular.otf</font>
+ </family>
+ <family lang="und-Newa">
+ <font weight="400" style="normal">NotoSansNewa-Regular.otf</font>
+ </family>
+ <family lang="und-Narb">
+ <font weight="400" style="normal">NotoSansOldNorthArabian-Regular.otf</font>
+ </family>
+ <family lang="und-Perm">
+ <font weight="400" style="normal">NotoSansOldPermic-Regular.otf</font>
+ </family>
+ <family lang="und-Hmng">
+ <font weight="400" style="normal">NotoSansPahawhHmong-Regular.otf</font>
+ </family>
+ <family lang="und-Palm">
+ <font weight="400" style="normal">NotoSansPalmyrene-Regular.otf</font>
+ </family>
+ <family lang="und-Pauc">
+ <font weight="400" style="normal">NotoSansPauCinHau-Regular.otf</font>
+ </family>
+ <family lang="und-Shrd">
+ <font weight="400" style="normal">NotoSansSharada-Regular.otf</font>
+ </family>
+ <family lang="und-Sora">
+ <font weight="400" style="normal">NotoSansSoraSompeng-Regular.otf</font>
+ </family>
+ <family lang="und-Gong">
+ <font weight="400" style="normal">NotoSansGunjalaGondi-Regular.otf</font>
+ </family>
+ <family lang="und-Rohg">
+ <font weight="400" style="normal">NotoSansHanifiRohingya-Regular.otf</font>
+ </family>
+ <family lang="und-Khoj">
+ <font weight="400" style="normal">NotoSansKhojki-Regular.otf</font>
+ </family>
+ <family lang="und-Gonm">
+ <font weight="400" style="normal">NotoSansMasaramGondi-Regular.otf</font>
+ </family>
+ <family lang="und-Wcho">
+ <font weight="400" style="normal">NotoSansWancho-Regular.otf</font>
+ </family>
+ <family lang="und-Wara">
+ <font weight="400" style="normal">NotoSansWarangCiti-Regular.otf</font>
+ </family>
+ <family lang="und-Gran">
+ <font weight="400" style="normal">NotoSansGrantha-Regular.ttf</font>
+ </family>
+ <family lang="und-Modi">
+ <font weight="400" style="normal">NotoSansModi-Regular.ttf</font>
+ </family>
+ <family lang="und-Dogr">
+ <font weight="400" style="normal">NotoSerifDogra-Regular.ttf</font>
+ </family>
+ <family lang="und-Medf">
+ <font weight="400" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
+ NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
+ NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
+ NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansMedefaidrin-Regular">
+ NotoSansMedefaidrin-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Soyo">
+ <font weight="400" style="normal" postScriptName="NotoSansSoyombo-Regular">
+ NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansSoyombo-Regular">
+ NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansSoyombo-Regular">
+ NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansSoyombo-Regular">
+ NotoSansSoyombo-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Takr">
+ <font weight="400" style="normal" postScriptName="NotoSansTakri-Regular">
+ NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSansTakri-Regular">
+ NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSansTakri-Regular">
+ NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSansTakri-Regular">
+ NotoSansTakri-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Hmnp">
+ <font weight="400" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
+ NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
+ NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
+ NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSerifHmongNyiakeng-Regular">
+ NotoSerifNyiakengPuachueHmong-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+ <family lang="und-Yezi">
+ <font weight="400" style="normal" postScriptName="NotoSerifYezidi-Regular">
+ NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="500" style="normal" postScriptName="NotoSerifYezidi-Regular">
+ NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="500"/>
+ </font>
+ <font weight="600" style="normal" postScriptName="NotoSerifYezidi-Regular">
+ NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="600"/>
+ </font>
+ <font weight="700" style="normal" postScriptName="NotoSerifYezidi-Regular">
+ NotoSerifYezidi-VF.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
+</familyset>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index e884f2f..5d1cc66 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -17,4 +17,5 @@
PRODUCT_PACKAGES := \
DroidSansMono.ttf \
AndroidClock.ttf \
+ font_fallback.xml \
fonts.xml
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 4a780bc..9320c14 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -1,5 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
+ DEPRECATED: This XML file is no longer a source of the font files installed
+ in the system.
+
+ For the device vendors: please add your font configurations to the
+ platform/frameworks/base/data/font_fallback.xml and also add it to this XML
+ file as much as possible for apps that reads this XML file.
+
+ For the application developers: please stop reading this XML file and use
+ android.graphics.fonts.SystemFonts#getAvailableFonts Java API or
+ ASystemFontIterator_open NDK API for getting list of system installed
+ font files.
+
WARNING: Parsing of this file by third-party apps is not supported. The
file, and the font files it refers to, will be renamed and/or moved out
from their respective location in the next Android release, and/or the
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 3fea65f..98629a2 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -47,7 +47,7 @@
public final class SystemFonts {
private static final String TAG = "SystemFonts";
- private static final String FONTS_XML = "/system/etc/fonts.xml";
+ private static final String FONTS_XML = "/system/etc/font_fallback.xml";
/** @hide */
public static final String SYSTEM_FONT_DIR = "/system/fonts/";
private static final String OEM_XML = "/product/etc/fonts_customization.xml";
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 3bb2564..2b1515a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import android.hardware.security.keymint.KeyParameter;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
@@ -299,6 +300,12 @@
return false;
}
+ private static boolean hasKeyMintV2() {
+ PackageManager pm = android.app.AppGlobals.getInitialApplication().getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_HARDWARE_KEYSTORE, 200)
+ && !pm.hasSystemFeature(PackageManager.FEATURE_HARDWARE_KEYSTORE, 300);
+ }
+
@Override
protected final void addAlgorithmSpecificParametersToBegin(
@NonNull List<KeyParameter> parameters, Authorization[] keyCharacteristics) {
@@ -307,11 +314,12 @@
KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest
));
// Only add the KM_TAG_RSA_OAEP_MGF_DIGEST tag to begin() if the MGF Digest is
- // present in the key properties. Keys generated prior to Android 14 did not have
- // this tag (Keystore didn't add it) so specifying any MGF digest tag would cause
- // a begin() operation (on an Android 14 device) to fail (with a key that was generated
- // on Android 13 or below).
- if (isMgfDigestTagPresentInKeyProperties(keyCharacteristics)) {
+ // present in the key properties or KeyMint version is 200. Keys generated prior to
+ // Android 14 did not have this tag (Keystore didn't add it) and hence not present in
+ // imported key as well, so specifying any MGF digest tag would cause a begin()
+ // operation (on an Android 14 device) to fail (with a key that was generated on
+ // Android 13 or below).
+ if (isMgfDigestTagPresentInKeyProperties(keyCharacteristics) || hasKeyMintV2()) {
parameters.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_RSA_OAEP_MGF_DIGEST, mKeymasterMgf1Digest
));
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 35e88ed..a605e2b 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -115,8 +115,7 @@
name: "protolog.json.gz",
srcs: [":generate-wm_shell_protolog.json"],
out: ["wmshell.protolog.json.gz"],
- cmd: "$(location minigzip) -c < $(in) > $(out)",
- tools: ["minigzip"],
+ cmd: "gzip -c < $(in) > $(out)",
}
prebuilt_etc {
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index ea44bea..9c5e0c4 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -79,7 +79,7 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Burbuja"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionar"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Burbuja cerrada."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Toca para reiniciar esta aplicación y obtener una mejor vista."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Toca para reiniciar esta aplicación y verlo mejor."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Problemas con la cámara?\nToca para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 39d717d..55697ca 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -79,7 +79,7 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"버블"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"관리"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"대화창을 닫았습니다."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"보기를 개선하려면 탭하여 앱을 다시 시작합니다."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"더 편하게 보기를 원하면 탭하여 앱을 다시 시작하세요."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"카메라 문제가 있나요?\n해결하려면 탭하세요."</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 14e8253..64fed1c 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -226,14 +226,12 @@
<dimen name="bubble_user_education_padding_end">58dp</dimen>
<!-- Padding between the bubble and the user education text. -->
<dimen name="bubble_user_education_stack_padding">16dp</dimen>
- <!-- Size of the bubble bar (height), should match transient_taskbar_size in Launcher. -->
- <dimen name="bubblebar_size">72dp</dimen>
- <!-- The size of the drag handle / menu shown along with a bubble bar expanded view. -->
- <dimen name="bubble_bar_expanded_view_handle_size">40dp</dimen>
- <!-- The width of the drag handle shown along with a bubble bar expanded view. -->
- <dimen name="bubble_bar_expanded_view_handle_width">128dp</dimen>
- <!-- The height of the drag handle shown along with a bubble bar expanded view. -->
- <dimen name="bubble_bar_expanded_view_handle_height">4dp</dimen>
+ <!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
+ <dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
+ <!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
+ <dimen name="bubble_bar_expanded_view_caption_dot_size">4dp</dimen>
+ <!-- The spacing between the dots for the caption menu in the bubble bar expanded view.. -->
+ <dimen name="bubble_bar_expanded_view_caption_dot_spacing">4dp</dimen>
<!-- Minimum width of the bubble bar manage menu. -->
<dimen name="bubble_bar_manage_menu_min_width">200dp</dimen>
<!-- Size of the dismiss icon in the bubble bar manage menu. -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 6880237..3eec513 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -329,16 +329,20 @@
new OneHandedTransitionCallback() {
@Override
public void onStartFinished(Rect bounds) {
- if (mStackView != null) {
- mStackView.onVerticalOffsetChanged(bounds.top);
- }
+ mMainExecutor.execute(() -> {
+ if (mStackView != null) {
+ mStackView.onVerticalOffsetChanged(bounds.top);
+ }
+ });
}
@Override
public void onStopFinished(Rect bounds) {
- if (mStackView != null) {
- mStackView.onVerticalOffsetChanged(bounds.top);
- }
+ mMainExecutor.execute(() -> {
+ if (mStackView != null) {
+ mStackView.onVerticalOffsetChanged(bounds.top);
+ }
+ });
}
});
}
@@ -1075,8 +1079,9 @@
* <p>This is used by external callers (launcher).
*/
@VisibleForTesting
- public void expandStackAndSelectBubbleFromLauncher(String key, boolean onLauncherHome) {
- mBubblePositioner.setShowingInBubbleBar(onLauncherHome);
+ public void expandStackAndSelectBubbleFromLauncher(String key, int bubbleBarXCoordinate,
+ int bubbleBarYCoordinate) {
+ mBubblePositioner.setBubbleBarPosition(bubbleBarXCoordinate, bubbleBarYCoordinate);
if (BubbleOverflow.KEY.equals(key)) {
mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
@@ -2087,9 +2092,10 @@
}
@Override
- public void showBubble(String key, boolean onLauncherHome) {
+ public void showBubble(String key, int bubbleBarXCoordinate, int bubbleBarYCoordinate) {
mMainExecutor.execute(
- () -> mController.expandStackAndSelectBubbleFromLauncher(key, onLauncherHome));
+ () -> mController.expandStackAndSelectBubbleFromLauncher(
+ key, bubbleBarXCoordinate, bubbleBarYCoordinate));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index cb08f93..6a5e310 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -22,6 +22,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -102,10 +103,7 @@
private int[] mPaddings = new int[4];
private boolean mShowingInBubbleBar;
- private boolean mBubblesOnHome;
- private int mBubbleBarSize;
- private int mBubbleBarHomeAdjustment;
- private final PointF mBubbleBarPosition = new PointF();
+ private final Point mBubbleBarPosition = new Point();
public BubblePositioner(Context context, WindowManager windowManager) {
mContext = context;
@@ -166,11 +164,9 @@
mSpacingBetweenBubbles = res.getDimensionPixelSize(R.dimen.bubble_spacing);
mDefaultMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
- mBubbleBarHomeAdjustment = mExpandedViewPadding / 2;
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleOffscreenAmount = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen);
mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
- mBubbleBarSize = res.getDimensionPixelSize(R.dimen.bubblebar_size);
if (mShowingInBubbleBar) {
mExpandedViewLargeScreenWidth = isLandscape()
@@ -722,11 +718,9 @@
mShowingInBubbleBar = showingInBubbleBar;
}
- /**
- * Sets whether bubbles are showing on launcher home, in which case positions are different.
- */
- public void setBubblesOnHome(boolean bubblesOnHome) {
- mBubblesOnHome = bubblesOnHome;
+ /** Sets the position of the bubble bar in screen coordinates. */
+ public void setBubbleBarPosition(int x, int y) {
+ mBubbleBarPosition.set(x, y);
}
/**
@@ -747,11 +741,7 @@
/** The bottom position of the expanded view when showing above the bubble bar. */
public int getExpandedViewBottomForBubbleBar() {
- return getAvailableRect().height()
- + mInsets.top
- - mBubbleBarSize
- - mExpandedViewPadding
- - getBubbleBarHomeAdjustment();
+ return mBubbleBarPosition.y - mExpandedViewPadding;
}
/**
@@ -764,19 +754,7 @@
/**
* Returns the on screen co-ordinates of the bubble bar.
*/
- public PointF getBubbleBarPosition() {
- mBubbleBarPosition.set(getAvailableRect().width() - mBubbleBarSize,
- getAvailableRect().height() - mBubbleBarSize
- - mExpandedViewPadding - getBubbleBarHomeAdjustment());
+ public Point getBubbleBarPosition() {
return mBubbleBarPosition;
}
-
- /**
- * When bubbles are shown on launcher home, there's an extra bit of padding that needs to
- * be applied between the expanded view and the bubble bar. This returns the adjustment value
- * if bubbles are showing on home.
- */
- private int getBubbleBarHomeAdjustment() {
- return mBubblesOnHome ? mBubbleBarHomeAdjustment : 0;
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index 20ae846..59332f4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -29,7 +29,8 @@
oneway void unregisterBubbleListener(in IBubblesListener listener) = 2;
- oneway void showBubble(in String key, in boolean onLauncherHome) = 3;
+ oneway void showBubble(in String key, in int bubbleBarXCoordinate,
+ in int bubbleBarYCoordinate) = 3;
oneway void removeBubble(in String key, in int reason) = 4;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index f729d02..b3602b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -21,10 +21,12 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.PointF;
+import android.graphics.Point;
import android.util.Log;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.animation.PhysicsAnimator;
import com.android.wm.shell.bubbles.BubbleOverflow;
@@ -111,7 +113,8 @@
/**
* Animates the provided bubble's expanded view to the expanded state.
*/
- public void animateExpansion(BubbleViewProvider expandedBubble) {
+ public void animateExpansion(BubbleViewProvider expandedBubble,
+ @Nullable Runnable afterAnimation) {
mExpandedBubble = expandedBubble;
if (mExpandedBubble == null) {
return;
@@ -133,7 +136,7 @@
bev.setVisibility(VISIBLE);
// Set the pivot point for the scale, so the view animates out from the bubble bar.
- PointF bubbleBarPosition = mPositioner.getBubbleBarPosition();
+ Point bubbleBarPosition = mPositioner.getBubbleBarPosition();
mExpandedViewContainerMatrix.setScale(
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
1f - EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT,
@@ -160,6 +163,9 @@
bev.setAnimationMatrix(null);
updateExpandedView();
bev.setSurfaceZOrderedOnTop(false);
+ if (afterAnimation != null) {
+ afterAnimation.run();
+ }
})
.start();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 396aa0e..6b6d6ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -16,12 +16,12 @@
package com.android.wm.shell.bubbles.bar;
-import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -63,7 +63,8 @@
private @Nullable TaskView mTaskView;
private @Nullable BubbleOverflowContainerView mOverflowView;
- private int mHandleHeight;
+ private int mCaptionHeight;
+
private int mBackgroundColor;
private float mCornerRadius = 0f;
@@ -97,8 +98,8 @@
super.onFinishInflate();
Context context = getContext();
setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation));
- mHandleHeight = context.getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_handle_size);
+ mCaptionHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_height);
addView(mHandleView);
applyThemeAttrs();
setClipToOutline(true);
@@ -136,6 +137,9 @@
addView(mTaskView);
mTaskView.setEnableSurfaceClipping(true);
mTaskView.setCornerRadius(mCornerRadius);
+
+ // Handle view needs to draw on top of task view.
+ bringChildToFront(mHandleView);
}
mMenuViewController = new BubbleBarMenuViewController(mContext, this);
mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
@@ -169,6 +173,10 @@
});
}
+ public BubbleBarHandleView getHandleView() {
+ return mHandleView;
+ }
+
// TODO (b/275087636): call this when theme/config changes
/** Updates the view based on the current theme. */
public void applyThemeAttrs() {
@@ -183,12 +191,12 @@
ta.recycle();
- mHandleHeight = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_handle_size);
+ mCaptionHeight = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_height);
if (mTaskView != null) {
mTaskView.setCornerRadius(mCornerRadius);
- updateHandleAndBackgroundColor(true /* animated */);
+ updateHandleColor(true /* animated */);
}
}
@@ -196,13 +204,12 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
- int menuViewHeight = Math.min(mHandleHeight, height);
+ int menuViewHeight = Math.min(mCaptionHeight, height);
measureChild(mHandleView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(menuViewHeight,
MeasureSpec.getMode(heightMeasureSpec)));
if (mTaskView != null) {
- int taskViewHeight = height - menuViewHeight;
- measureChild(mTaskView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(taskViewHeight,
+ measureChild(mTaskView, widthMeasureSpec, MeasureSpec.makeMeasureSpec(height,
MeasureSpec.getMode(heightMeasureSpec)));
}
}
@@ -210,19 +217,20 @@
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- // Drag handle above
- final int dragHandleBottom = t + mHandleView.getMeasuredHeight();
- mHandleView.layout(l, t, r, dragHandleBottom);
+ final int captionBottom = t + mCaptionHeight;
if (mTaskView != null) {
- mTaskView.layout(l, dragHandleBottom, r,
- dragHandleBottom + mTaskView.getMeasuredHeight());
+ mTaskView.layout(l, t, r,
+ t + mTaskView.getMeasuredHeight());
+ mTaskView.setCaptionInsets(Insets.of(0, mCaptionHeight, 0, 0));
}
+ // Handle draws on top of task view in the caption area.
+ mHandleView.layout(l, t, r, captionBottom);
}
@Override
public void onTaskCreated() {
setContentVisibility(true);
- updateHandleAndBackgroundColor(false /* animated */);
+ updateHandleColor(false /* animated */);
}
@Override
@@ -298,33 +306,20 @@
}
/**
- * Updates the background color to match with task view status/bg color, and sets handle color
- * to contrast with the background
+ * Updates the handle color based on the task view status bar or background color; if those
+ * are transparent it defaults to the background color pulled from system theme attributes.
*/
- private void updateHandleAndBackgroundColor(boolean animated) {
- if (mTaskView == null) return;
- final int color = getTaskViewColor();
- final boolean isRegionDark = Color.luminance(color) <= 0.5;
- mHandleView.updateHandleColor(isRegionDark, animated);
- setBackgroundColor(color);
- }
-
- /**
- * Retrieves task view status/nav bar color or background if available
- *
- * TODO (b/283075226): Update with color sampling when
- * RegionSamplingHelper or alternative is available
- */
- private @ColorInt int getTaskViewColor() {
- if (mTaskView == null || mTaskView.getTaskInfo() == null) return mBackgroundColor;
+ private void updateHandleColor(boolean animated) {
+ if (mTaskView == null || mTaskView.getTaskInfo() == null) return;
+ int color = mBackgroundColor;
ActivityManager.TaskDescription taskDescription = mTaskView.getTaskInfo().taskDescription;
if (taskDescription.getStatusBarColor() != Color.TRANSPARENT) {
- return taskDescription.getStatusBarColor();
+ color = taskDescription.getStatusBarColor();
} else if (taskDescription.getBackgroundColor() != Color.TRANSPARENT) {
- return taskDescription.getBackgroundColor();
- } else {
- return mBackgroundColor;
+ color = taskDescription.getBackgroundColor();
}
+ final boolean isRegionDark = Color.luminance(color) <= 0.5;
+ mHandleView.updateHandleColor(isRegionDark, animated);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
index ce26bc0..2b7a070 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java
@@ -21,7 +21,8 @@
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Outline;
-import android.graphics.Rect;
+import android.graphics.Path;
+import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
@@ -37,8 +38,12 @@
public class BubbleBarHandleView extends View {
private static final long COLOR_CHANGE_DURATION = 120;
- private int mHandleWidth;
- private int mHandleHeight;
+ // The handle view is currently rendered as 3 evenly spaced dots.
+ private int mDotSize;
+ private int mDotSpacing;
+ // Path used to draw the dots
+ private final Path mPath = new Path();
+
private @ColorInt int mHandleLightColor;
private @ColorInt int mHandleDarkColor;
private @Nullable ObjectAnimator mColorChangeAnim;
@@ -58,11 +63,10 @@
public BubbleBarHandleView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
-
- mHandleWidth = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_handle_width);
- mHandleHeight = getResources().getDimensionPixelSize(
- R.dimen.bubble_bar_expanded_view_handle_height);
+ mDotSize = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_dot_size);
+ mDotSpacing = getResources().getDimensionPixelSize(
+ R.dimen.bubble_bar_expanded_view_caption_dot_spacing);
mHandleLightColor = ContextCompat.getColor(getContext(),
R.color.bubble_bar_expanded_view_handle_light);
mHandleDarkColor = ContextCompat.getColor(getContext(),
@@ -74,13 +78,26 @@
public void getOutline(View view, Outline outline) {
final int handleCenterX = view.getWidth() / 2;
final int handleCenterY = view.getHeight() / 2;
- final float handleRadius = mHandleHeight / 2f;
- Rect handleBounds = new Rect(
- handleCenterX - mHandleWidth / 2,
- handleCenterY - mHandleHeight / 2,
- handleCenterX + mHandleWidth / 2,
- handleCenterY + mHandleHeight / 2);
- outline.setRoundRect(handleBounds, handleRadius);
+ final int handleTotalWidth = mDotSize * 3 + mDotSpacing * 2;
+ final int handleLeft = handleCenterX - handleTotalWidth / 2;
+ final int handleTop = handleCenterY - mDotSize / 2;
+ final int handleBottom = handleTop + mDotSize;
+ RectF dot1 = new RectF(
+ handleLeft, handleTop,
+ handleLeft + mDotSize, handleBottom);
+ RectF dot2 = new RectF(
+ dot1.right + mDotSpacing, handleTop,
+ dot1.right + mDotSpacing + mDotSize, handleBottom
+ );
+ RectF dot3 = new RectF(
+ dot2.right + mDotSpacing, handleTop,
+ dot2.right + mDotSpacing + mDotSize, handleBottom
+ );
+ mPath.reset();
+ mPath.addOval(dot1, Path.Direction.CW);
+ mPath.addOval(dot2, Path.Direction.CW);
+ mPath.addOval(dot3, Path.Direction.CW);
+ outline.setPath(mPath);
}
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index d20b33e..8ead18b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -24,6 +24,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
+import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
@@ -68,6 +69,10 @@
private final Region mTouchableRegion = new Region();
private final Rect mTempRect = new Rect();
+ // Used to ensure touch target size for the menu shown on a bubble expanded view
+ private TouchDelegate mHandleTouchDelegate;
+ private final Rect mHandleTouchBounds = new Rect();
+
public BubbleBarLayerView(Context context, BubbleController controller) {
super(context);
mBubbleController = controller;
@@ -164,7 +169,17 @@
mIsExpanded = true;
mBubbleController.getSysuiProxy().onStackExpandChanged(true);
- mAnimationHelper.animateExpansion(mExpandedBubble);
+ mAnimationHelper.animateExpansion(mExpandedBubble, () -> {
+ if (mExpandedView == null) return;
+ // Touch delegate for the menu
+ BubbleBarHandleView view = mExpandedView.getHandleView();
+ view.getBoundsOnScreen(mHandleTouchBounds);
+ mHandleTouchBounds.top -= mPositioner.getBubblePaddingTop();
+ mHandleTouchDelegate = new TouchDelegate(mHandleTouchBounds,
+ mExpandedView.getHandleView());
+ setTouchDelegate(mHandleTouchDelegate);
+ });
+
showScrim(true);
}
@@ -175,6 +190,7 @@
mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
mBubbleController.getSysuiProxy().onStackExpandChanged(false);
mExpandedView = null;
+ setTouchDelegate(null);
showScrim(false);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 40ea276..6d14440 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -63,6 +63,7 @@
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.util.KtProtoLog
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
+import com.android.wm.shell.windowdecor.MoveToDesktopAnimator
import java.io.PrintWriter
import java.util.concurrent.Executor
import java.util.function.Consumer
@@ -204,7 +205,11 @@
* Moves a single task to freeform and sets the taskBounds to the passed in bounds,
* startBounds
*/
- fun moveToFreeform(taskInfo: RunningTaskInfo, startBounds: Rect) {
+ fun moveToFreeform(
+ taskInfo: RunningTaskInfo,
+ startBounds: Rect,
+ dragToDesktopValueAnimator: MoveToDesktopAnimator
+ ) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: moveToFreeform with bounds taskId=%d",
@@ -216,8 +221,8 @@
wct.setBounds(taskInfo.token, startBounds)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_FREEFORM, wct, mOnAnimationFinishedCallback)
+ enterDesktopTaskTransitionHandler.startMoveToFreeformAnimation(wct,
+ dragToDesktopValueAnimator, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
}
@@ -270,7 +275,7 @@
* Move a task to fullscreen after being dragged from fullscreen and released back into
* status bar area
*/
- fun cancelMoveToFreeform(task: RunningTaskInfo, position: Point) {
+ fun cancelMoveToFreeform(task: RunningTaskInfo, moveToDesktopAnimator: MoveToDesktopAnimator) {
KtProtoLog.v(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: cancelMoveToFreeform taskId=%d",
@@ -280,8 +285,8 @@
wct.setBounds(task.token, null)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(
- wct, position) { t ->
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct,
+ moveToDesktopAnimator) { t ->
val callbackWCT = WindowContainerTransaction()
visualIndicator?.releaseVisualIndicator(t)
visualIndicator = null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 3e175f3..650cac5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -22,9 +22,10 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
-import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
+import android.util.Slog;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.TransitionInfo;
@@ -35,6 +36,7 @@
import androidx.annotation.Nullable;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.MoveToDesktopAnimator;
import java.util.ArrayList;
import java.util.List;
@@ -47,18 +49,17 @@
*/
public class EnterDesktopTaskTransitionHandler implements Transitions.TransitionHandler {
+ private static final String TAG = "EnterDesktopTaskTransitionHandler";
private final Transitions mTransitions;
private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
- // The size of the screen during drag relative to the fullscreen size
- public static final float DRAG_FREEFORM_SCALE = 0.4f;
// The size of the screen after drag relative to the fullscreen size
public static final float FINAL_FREEFORM_SCALE = 0.6f;
public static final int FREEFORM_ANIMATION_DURATION = 336;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
- private Point mPosition;
private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
+ private MoveToDesktopAnimator mMoveToDesktopAnimator;
public EnterDesktopTaskTransitionHandler(
Transitions transitions) {
@@ -87,15 +88,30 @@
}
/**
+ * Starts Transition of type TRANSIT_ENTER_FREEFORM
+ * @param wct WindowContainerTransaction for transition
+ * @param moveToDesktopAnimator Animator that shrinks and positions task during two part move
+ * to desktop animation
+ * @param onAnimationEndCallback to be called after animation
+ */
+ public void startMoveToFreeformAnimation(@NonNull WindowContainerTransaction wct,
+ @NonNull MoveToDesktopAnimator moveToDesktopAnimator,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mMoveToDesktopAnimator = moveToDesktopAnimator;
+ startTransition(Transitions.TRANSIT_ENTER_FREEFORM, wct, onAnimationEndCallback);
+ }
+
+ /**
* Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
* @param wct WindowContainerTransaction for transition
- * @param position Position of task when transition is triggered
+ * @param moveToDesktopAnimator Animator that shrinks and positions task during two part move
+ * to desktop animation
* @param onAnimationEndCallback to be called after animation
*/
public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
- Point position,
+ MoveToDesktopAnimator moveToDesktopAnimator,
Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
- mPosition = position;
+ mMoveToDesktopAnimator = moveToDesktopAnimator;
startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct,
onAnimationEndCallback);
}
@@ -145,9 +161,23 @@
// to null and we don't require an animation
final SurfaceControl sc = change.getLeash();
startT.setWindowCrop(sc, null);
+
+ if (mMoveToDesktopAnimator == null
+ || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
+ Slog.e(TAG, "No animator available for this transition");
+ return false;
+ }
+
+ // Calculate and set position of the task
+ final PointF position = mMoveToDesktopAnimator.getPosition();
+ startT.setPosition(sc, position.x, position.y);
+ finishT.setPosition(sc, position.x, position.y);
+
startT.apply();
+
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
+
return true;
}
@@ -162,12 +192,18 @@
endBounds.height());
startT.apply();
+ // End the animation that shrinks the window when task is first dragged from fullscreen
+ if (mMoveToDesktopAnimator != null) {
+ mMoveToDesktopAnimator.endAnimator();
+ }
+
// We want to find the scale of the current bounds relative to the end bounds. The
// task is currently scaled to DRAG_FREEFORM_SCALE and the final bounds will be
// scaled to FINAL_FREEFORM_SCALE. So, it is scaled to
// DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE relative to the freeform bounds
final ValueAnimator animator =
- ValueAnimator.ofFloat(DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE, 1f);
+ ValueAnimator.ofFloat(
+ MoveToDesktopAnimator.DRAG_FREEFORM_SCALE / FINAL_FREEFORM_SCALE, 1f);
animator.setDuration(FREEFORM_ANIMATION_DURATION);
final SurfaceControl.Transaction t = mTransactionSupplier.get();
animator.addUpdateListener(animation -> {
@@ -199,8 +235,7 @@
}
if (type == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
- && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
- && mPosition != null) {
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
// This Transition animates a task to fullscreen after being dragged from the status
// bar and then released back into the status bar area
final SurfaceControl sc = change.getLeash();
@@ -210,13 +245,27 @@
.setWindowCrop(sc, endBounds.width(), endBounds.height())
.apply();
+ if (mMoveToDesktopAnimator == null
+ || mMoveToDesktopAnimator.getTaskId() != change.getTaskInfo().taskId) {
+ Slog.e(TAG, "No animator available for this transition");
+ return false;
+ }
+
+ // End the animation that shrinks the window when task is first dragged from fullscreen
+ mMoveToDesktopAnimator.endAnimator();
+
final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(DRAG_FREEFORM_SCALE, 1f);
+ animator.setFloatValues(MoveToDesktopAnimator.DRAG_FREEFORM_SCALE, 1f);
animator.setDuration(FREEFORM_ANIMATION_DURATION);
final SurfaceControl.Transaction t = mTransactionSupplier.get();
+
+ // Get position of the task
+ final float x = mMoveToDesktopAnimator.getPosition().x;
+ final float y = mMoveToDesktopAnimator.getPosition().y;
+
animator.addUpdateListener(animation -> {
final float scale = (float) animation.getAnimatedValue();
- t.setPosition(sc, mPosition.x * (1 - scale), mPosition.y * (1 - scale))
+ t.setPosition(sc, x * (1 - scale), y * (1 - scale))
.setScale(sc, scale, scale)
.show(sc)
.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index be2489d..0bf8ec3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -16,9 +16,6 @@
package com.android.wm.shell.draganddrop;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
-import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DragEvent.ACTION_DRAG_ENDED;
import static android.view.DragEvent.ACTION_DRAG_ENTERED;
@@ -38,6 +35,7 @@
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
+import android.app.ActivityTaskManager;
import android.content.ClipDescription;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -205,8 +203,6 @@
final Context context = mDisplayController.getDisplayContext(displayId)
.createWindowContext(TYPE_APPLICATION_OVERLAY, null);
final WindowManager wm = context.getSystemService(WindowManager.class);
-
- // TODO(b/169894807): Figure out the right layer for this, needs to be below the task bar
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
TYPE_APPLICATION_OVERLAY,
@@ -279,15 +275,11 @@
}
if (event.getAction() == ACTION_DRAG_STARTED) {
- final boolean hasValidClipData = event.getClipData().getItemCount() > 0
- && (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
- || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
- || description.hasMimeType(MIMETYPE_APPLICATION_TASK));
- pd.isHandlingDrag = hasValidClipData;
+ pd.isHandlingDrag = DragUtils.canHandleDrag(event);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP,
"Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s",
pd.isHandlingDrag, event.getClipData().getItemCount(),
- getMimeTypes(description));
+ DragUtils.getMimeTypesConcatenated(description));
}
if (!pd.isHandlingDrag) {
@@ -300,10 +292,13 @@
Slog.w(TAG, "Unexpected drag start during an active drag");
return false;
}
+ // TODO(b/290391688): Also update the session data with task stack changes
InstanceId loggerSessionId = mLogger.logStart(event);
pd.activeDragCount++;
- pd.dragLayout.prepare(mDisplayController.getDisplayLayout(displayId),
- event.getClipData(), loggerSessionId);
+ pd.dragSession = new DragSession(mContext, ActivityTaskManager.getInstance(),
+ mDisplayController.getDisplayLayout(displayId), event.getClipData());
+ pd.dragSession.update();
+ pd.dragLayout.prepare(pd.dragSession, loggerSessionId);
setDropTargetWindowVisibility(pd, View.VISIBLE);
notifyDragStarted();
break;
@@ -324,7 +319,7 @@
break;
}
case ACTION_DRAG_ENDED:
- // TODO(b/169894807): Ensure sure it's not possible to get ENDED without DROP
+ // TODO(b/290391688): Ensure sure it's not possible to get ENDED without DROP
// or EXITED
if (pd.dragLayout.hasDropped()) {
mLogger.logDrop();
@@ -362,17 +357,6 @@
pd.setWindowVisibility(visibility);
}
- private String getMimeTypes(ClipDescription description) {
- String mimeTypes = "";
- for (int i = 0; i < description.getMimeTypeCount(); i++) {
- if (i > 0) {
- mimeTypes += ", ";
- }
- mimeTypes += description.getMimeType(i);
- }
- return mimeTypes;
- }
-
/**
* Returns if any displays are currently ready to handle a drag/drop.
*/
@@ -462,6 +446,8 @@
// A count of the number of active drags in progress to ensure that we only hide the window
// when all the drag animations have completed
int activeDragCount;
+ // The active drag session
+ DragSession dragSession;
PerDisplay(int dispId, Context c, WindowManager w, FrameLayout rv, DragLayout dl) {
displayId = dispId;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index fb08c87..e70768b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -21,7 +21,6 @@
import static android.app.ComponentOptions.KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.ClipDescription.EXTRA_ACTIVITY_OPTIONS;
import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
@@ -41,16 +40,13 @@
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT;
import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP;
-import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
-import android.app.WindowConfiguration;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -67,14 +63,12 @@
import com.android.internal.logging.InstanceId;
import com.android.wm.shell.R;
-import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.List;
/**
* The policy for handling drag and drop operations to shell.
@@ -84,7 +78,6 @@
private static final String TAG = DragAndDropPolicy.class.getSimpleName();
private final Context mContext;
- private final ActivityTaskManager mActivityTaskManager;
private final Starter mStarter;
private final SplitScreenController mSplitScreen;
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
@@ -94,14 +87,12 @@
private DragSession mSession;
public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
- this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context));
+ this(context, splitScreen, new DefaultStarter(context));
}
@VisibleForTesting
- DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
- SplitScreenController splitScreen, Starter starter) {
+ DragAndDropPolicy(Context context, SplitScreenController splitScreen, Starter starter) {
mContext = context;
- mActivityTaskManager = activityTaskManager;
mSplitScreen = splitScreen;
mStarter = mSplitScreen != null ? mSplitScreen : starter;
}
@@ -109,11 +100,9 @@
/**
* Starts a new drag session with the given initial drag data.
*/
- void start(DisplayLayout displayLayout, ClipData data, InstanceId loggerSessionId) {
+ void start(DragSession session, InstanceId loggerSessionId) {
mLoggerSessionId = loggerSessionId;
- mSession = new DragSession(mActivityTaskManager, displayLayout, data);
- // TODO(b/169894807): Also update the session data with task stack changes
- mSession.update();
+ mSession = session;
RectF disallowHitRegion = (RectF) mSession.dragData.getExtra(EXTRA_DISALLOW_HIT_REGION);
if (disallowHitRegion == null) {
mDisallowHitRegion.setEmpty();
@@ -123,13 +112,6 @@
}
/**
- * Returns the last running task.
- */
- ActivityManager.RunningTaskInfo getLatestRunningTask() {
- return mSession.runningTaskInfo;
- }
-
- /**
* Returns the number of targets.
*/
int getNumTargets() {
@@ -286,49 +268,6 @@
}
/**
- * Per-drag session data.
- */
- private static class DragSession {
- private final ActivityTaskManager mActivityTaskManager;
- private final ClipData mInitialDragData;
-
- final DisplayLayout displayLayout;
- Intent dragData;
- ActivityManager.RunningTaskInfo runningTaskInfo;
- @WindowConfiguration.WindowingMode
- int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
- @WindowConfiguration.ActivityType
- int runningTaskActType = ACTIVITY_TYPE_STANDARD;
- boolean dragItemSupportsSplitscreen;
-
- DragSession(ActivityTaskManager activityTaskManager,
- DisplayLayout dispLayout, ClipData data) {
- mActivityTaskManager = activityTaskManager;
- mInitialDragData = data;
- displayLayout = dispLayout;
- }
-
- /**
- * Updates the session data based on the current state of the system.
- */
- void update() {
- List<ActivityManager.RunningTaskInfo> tasks =
- mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
- if (!tasks.isEmpty()) {
- final ActivityManager.RunningTaskInfo task = tasks.get(0);
- runningTaskInfo = task;
- runningTaskWinMode = task.getWindowingMode();
- runningTaskActType = task.getActivityType();
- }
-
- final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
- dragItemSupportsSplitscreen = info == null
- || ActivityInfo.isResizeableMode(info.resizeMode);
- dragData = mInitialDragData.getItemAt(0).getIntent();
- }
- }
-
- /**
* Interface for actually committing the task launches.
*/
public interface Starter {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index fe42822a..205a455 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -35,7 +35,6 @@
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.StatusBarManager;
-import android.content.ClipData;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Color;
@@ -53,14 +52,13 @@
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
-import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.ArrayList;
/**
- * Coordinates the visible drop targets for the current drag.
+ * Coordinates the visible drop targets for the current drag within a single display.
*/
public class DragLayout extends LinearLayout {
@@ -86,6 +84,7 @@
private boolean mIsShowing;
private boolean mHasDropped;
+ private DragSession mSession;
@SuppressLint("WrongConstant")
public DragLayout(Context context, SplitScreenController splitScreenController,
@@ -182,16 +181,19 @@
return mHasDropped;
}
- public void prepare(DisplayLayout displayLayout, ClipData initialData,
- InstanceId loggerSessionId) {
- mPolicy.start(displayLayout, initialData, loggerSessionId);
+ /**
+ * Called when a new drag is started.
+ */
+ public void prepare(DragSession session, InstanceId loggerSessionId) {
+ mPolicy.start(session, loggerSessionId);
+ mSession = session;
mHasDropped = false;
mCurrentTarget = null;
boolean alreadyInSplit = mSplitScreenController != null
&& mSplitScreenController.isSplitScreenVisible();
if (!alreadyInSplit) {
- ActivityManager.RunningTaskInfo taskInfo1 = mPolicy.getLatestRunningTask();
+ ActivityManager.RunningTaskInfo taskInfo1 = mSession.runningTaskInfo;
if (taskInfo1 != null) {
final int activityType = taskInfo1.getActivityType();
if (activityType == ACTIVITY_TYPE_STANDARD) {
@@ -356,7 +358,16 @@
*/
public void hide(DragEvent event, Runnable hideCompleteCallback) {
mIsShowing = false;
- animateSplitContainers(false, hideCompleteCallback);
+ animateSplitContainers(false, () -> {
+ if (hideCompleteCallback != null) {
+ hideCompleteCallback.run();
+ }
+ switch (event.getAction()) {
+ case DragEvent.ACTION_DROP:
+ case DragEvent.ACTION_DRAG_ENDED:
+ mSession = null;
+ }
+ });
// Reset the state if we previously force-ignore the bottom margin
mDropZoneView1.setForceIgnoreBottomMargin(false);
mDropZoneView2.setForceIgnoreBottomMargin(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
new file mode 100644
index 0000000..478b6a9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.ClipDescription.EXTRA_PENDING_INTENT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+import static android.content.Intent.EXTRA_USER;
+
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
+import android.app.WindowConfiguration;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.net.Uri;
+import android.os.UserHandle;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.common.DisplayLayout;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * Per-drag session data.
+ */
+public class DragSession {
+ private final ActivityTaskManager mActivityTaskManager;
+ private final ClipData mInitialDragData;
+
+ final DisplayLayout displayLayout;
+ Intent dragData;
+ ActivityManager.RunningTaskInfo runningTaskInfo;
+ @WindowConfiguration.WindowingMode
+ int runningTaskWinMode = WINDOWING_MODE_UNDEFINED;
+ @WindowConfiguration.ActivityType
+ int runningTaskActType = ACTIVITY_TYPE_STANDARD;
+ boolean dragItemSupportsSplitscreen;
+
+ DragSession(Context context, ActivityTaskManager activityTaskManager,
+ DisplayLayout dispLayout, ClipData data) {
+ mActivityTaskManager = activityTaskManager;
+ mInitialDragData = data;
+ displayLayout = dispLayout;
+ }
+
+ /**
+ * Updates the session data based on the current state of the system.
+ */
+ void update() {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ mActivityTaskManager.getTasks(1, false /* filterOnlyVisibleRecents */);
+ if (!tasks.isEmpty()) {
+ final ActivityManager.RunningTaskInfo task = tasks.get(0);
+ runningTaskInfo = task;
+ runningTaskWinMode = task.getWindowingMode();
+ runningTaskActType = task.getActivityType();
+ }
+
+ final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo();
+ dragItemSupportsSplitscreen = info == null
+ || ActivityInfo.isResizeableMode(info.resizeMode);
+ dragData = mInitialDragData.getItemAt(0).getIntent();
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
new file mode 100644
index 0000000..7c0883d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT;
+import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK;
+
+import android.content.ClipDescription;
+import android.view.DragEvent;
+
+/** Collection of utility classes for handling drag and drop. */
+public class DragUtils {
+ private static final String TAG = "DragUtils";
+
+ /**
+ * Returns whether we can handle this particular drag.
+ */
+ public static boolean canHandleDrag(DragEvent event) {
+ return event.getClipData().getItemCount() > 0
+ && (isAppDrag(event.getClipDescription()));
+ }
+
+ /**
+ * Returns whether this clip data description represents an app drag.
+ */
+ public static boolean isAppDrag(ClipDescription description) {
+ return description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
+ || description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT)
+ || description.hasMimeType(MIMETYPE_APPLICATION_TASK);
+ }
+
+ /**
+ * Returns a list of the mime types provided in the clip description.
+ */
+ public static String getMimeTypesConcatenated(ClipDescription description) {
+ String mimeTypes = "";
+ for (int i = 0; i < description.getMimeTypeCount(); i++) {
+ if (i > 0) {
+ mimeTypes += ", ";
+ }
+ mimeTypes += description.getMimeType(i);
+ }
+ return mimeTypes;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
deleted file mode 100644
index 73deea5..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.draganddrop;
-
-import android.animation.ObjectAnimator;
-import android.animation.RectEvaluator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.IntProperty;
-import android.util.Property;
-import android.view.animation.Interpolator;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.graphics.ColorUtils;
-import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.protolog.ShellProtoLogGroup;
-import com.android.wm.shell.R;
-
-/**
- * Drawable to draw the region that the target will have once it is dropped.
- */
-public class DropOutlineDrawable extends Drawable {
-
- private static final int BOUNDS_DURATION = 200;
- private static final int ALPHA_DURATION = 135;
-
- private final IntProperty<DropOutlineDrawable> ALPHA =
- new IntProperty<DropOutlineDrawable>("alpha") {
- @Override
- public void setValue(DropOutlineDrawable d, int alpha) {
- d.setAlpha(alpha);
- }
-
- @Override
- public Integer get(DropOutlineDrawable d) {
- return d.getAlpha();
- }
- };
-
- private final Property<DropOutlineDrawable, Rect> BOUNDS =
- new Property<DropOutlineDrawable, Rect>(Rect.class, "bounds") {
- @Override
- public void set(DropOutlineDrawable d, Rect bounds) {
- d.setRegionBounds(bounds);
- }
-
- @Override
- public Rect get(DropOutlineDrawable d) {
- return d.getRegionBounds();
- }
- };
-
- private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
- private ObjectAnimator mBoundsAnimator;
- private ObjectAnimator mAlphaAnimator;
-
- private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private final Rect mBounds = new Rect();
- private final float mCornerRadius;
- private final int mMaxAlpha;
- private int mColor;
-
- public DropOutlineDrawable(Context context) {
- super();
- // TODO(b/169894807): Use corner specific radii and maybe lower radius for non-edge corners
- mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mColor = context.getColor(R.color.drop_outline_background);
- mMaxAlpha = Color.alpha(mColor);
- // Initialize as hidden
- ALPHA.set(this, 0);
- }
-
- @Override
- public void setColorFilter(@Nullable ColorFilter colorFilter) {
- // Do nothing
- }
-
- @Override
- public void setAlpha(int alpha) {
- mColor = ColorUtils.setAlphaComponent(mColor, alpha);
- mPaint.setColor(mColor);
- invalidateSelf();
- }
-
- @Override
- public int getAlpha() {
- return Color.alpha(mColor);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- protected void onBoundsChange(Rect bounds) {
- invalidateSelf();
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- canvas.drawRoundRect(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom,
- mCornerRadius, mCornerRadius, mPaint);
- }
-
- public void setRegionBounds(Rect bounds) {
- mBounds.set(bounds);
- invalidateSelf();
- }
-
- public Rect getRegionBounds() {
- return mBounds;
- }
-
- ObjectAnimator startBoundsAnimation(Rect toBounds, Interpolator interpolator) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Animate bounds: from=%s to=%s",
- mBounds, toBounds);
- if (mBoundsAnimator != null) {
- mBoundsAnimator.cancel();
- }
- mBoundsAnimator = ObjectAnimator.ofObject(this, BOUNDS, mRectEvaluator,
- mBounds, toBounds);
- mBoundsAnimator.setDuration(BOUNDS_DURATION);
- mBoundsAnimator.setInterpolator(interpolator);
- mBoundsAnimator.start();
- return mBoundsAnimator;
- }
-
- ObjectAnimator startVisibilityAnimation(boolean visible, Interpolator interpolator) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Animate alpha: from=%d to=%d",
- Color.alpha(mColor), visible ? mMaxAlpha : 0);
- if (mAlphaAnimator != null) {
- mAlphaAnimator.cancel();
- }
- mAlphaAnimator = ObjectAnimator.ofInt(this, ALPHA, Color.alpha(mColor),
- visible ? mMaxAlpha : 0);
- mAlphaAnimator.setDuration(ALPHA_DURATION);
- mAlphaAnimator.setInterpolator(interpolator);
- mAlphaAnimator.start();
- return mAlphaAnimator;
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
index 7971c04..c6e5cf2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
@@ -123,18 +123,19 @@
final int totalVerticalPadding = getInsetBounds().top
+ (getDisplayBounds().height() - getInsetBounds().bottom);
- final int shorterLength = (int) (1f * Math.min(
- getDisplayBounds().width() - totalHorizontalPadding,
- getDisplayBounds().height() - totalVerticalPadding));
+ final int shorterLength = Math.min(getDisplayBounds().width() - totalHorizontalPadding,
+ getDisplayBounds().height() - totalVerticalPadding);
int maxWidth, maxHeight;
// use the optimized max sizing logic only within a certain aspect ratio range
if (aspectRatio >= mOptimizedAspectRatio && aspectRatio <= 1 / mOptimizedAspectRatio) {
// this formula and its derivation is explained in b/198643358#comment16
- maxWidth = (int) (mOptimizedAspectRatio * shorterLength
+ maxWidth = Math.round(mOptimizedAspectRatio * shorterLength
+ shorterLength * (aspectRatio - mOptimizedAspectRatio) / (1
+ aspectRatio));
+ // make sure the max width doesn't go beyond shorter screen length after rounding
+ maxWidth = Math.min(maxWidth, shorterLength);
maxHeight = Math.round(maxWidth / aspectRatio);
} else {
if (aspectRatio > 1f) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index b0fa993..3af1b75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -35,7 +35,7 @@
WM_SHELL_RECENTS_TRANSITION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
"ShellRecents"),
WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
- Consts.TAG_WM_SHELL),
+ "ShellDragAndDrop"),
WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM_STARTING_WINDOW),
WM_SHELL_BACK_PREVIEW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 837f118..39b6675 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -573,10 +573,12 @@
}
final boolean isRootTask = taskInfo != null
&& TransitionInfo.isIndependent(change, info);
+ final boolean isRecentsTask = mRecentsTask != null
+ && mRecentsTask.equals(change.getContainer());
hasTaskChange = hasTaskChange || isRootTask;
final boolean isLeafTask = leafTaskFilter.test(change);
if (TransitionUtil.isOpeningType(change.getMode())) {
- if (mRecentsTask != null && mRecentsTask.equals(change.getContainer())) {
+ if (isRecentsTask) {
recentsOpening = change;
} else if (isRootTask || isLeafTask) {
if (isLeafTask && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
@@ -591,7 +593,7 @@
openingTaskIsLeafs.add(isLeafTask ? 1 : 0);
}
} else if (TransitionUtil.isClosingType(change.getMode())) {
- if (mRecentsTask != null && mRecentsTask.equals(change.getContainer())) {
+ if (isRecentsTask) {
foundRecentsClosing = true;
} else if (isRootTask || isLeafTask) {
if (closingTasks == null) {
@@ -612,7 +614,7 @@
if (!TransitionUtil.isOrderOnly(change) && isLeafTask) {
hasChangingApp = true;
} else if (isLeafTask && taskInfo.topActivityType == ACTIVITY_TYPE_HOME
- && !mRecentsTask.equals(change.getContainer())) {
+ && !isRecentsTask ) {
// Unless it is a 3p launcher. This means that the 3p launcher was already
// visible (eg. the "pausing" task is translucent over the 3p launcher).
// Treat it as if we are "re-opening" the 3p launcher.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 3669bce..af8ef17 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -624,8 +624,8 @@
Toast.LENGTH_SHORT).show();
}
}
- mStageCoordinator.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
- splitPosition, splitRatio, remoteTransition, instanceId);
+ mStageCoordinator.startShortcutAndTask(shortcutInfo, activityOptions.toBundle(), taskId,
+ options2, splitPosition, splitRatio, remoteTransition, instanceId);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 6961dab..283be9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -219,6 +219,8 @@
private boolean mIsDropEntering;
private boolean mIsExiting;
private boolean mIsRootTranslucent;
+ @VisibleForTesting
+ int mTopStageAfterFoldDismiss;
private DefaultMixedHandler mMixedHandler;
private final Toast mSplitUnsupportedToast;
@@ -738,12 +740,12 @@
mMainStage.activate(wct, false /* reparent */);
}
+ setSideStagePosition(splitPosition, wct);
mSplitLayout.setDivideRatio(splitRatio);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
setRootForceTranslucent(false, wct);
- setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
if (shortcutInfo1 != null) {
@@ -1310,6 +1312,24 @@
final StageTaskListener toTop = mainStageVisible ? mMainStage : mSideStage;
exitSplitScreen(toTop, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
}
+
+ // Dismiss split if the flag record any side of stages.
+ if (mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+ if (ENABLE_SHELL_TRANSITIONS) {
+ // Need manually clear here due to this transition might be aborted due to keyguard
+ // on top and lead to no visible change.
+ clearSplitPairedInRecents(EXIT_REASON_DEVICE_FOLDED);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
+ mSplitTransitions.startDismissTransition(wct, this,
+ mTopStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
+ } else {
+ exitSplitScreen(
+ mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
+ EXIT_REASON_DEVICE_FOLDED);
+ }
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ }
}
void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
@@ -1346,15 +1366,8 @@
if (!mMainStage.isActive() || mIsExiting) return;
onSplitScreenExit();
+ clearSplitPairedInRecents(exitReason);
- mRecentTasks.ifPresent(recentTasks -> {
- // Notify recents if we are exiting in a way that breaks the pair, and disable further
- // updates to splits in the recents until we enter split again
- if (shouldBreakPairedTaskInRecents(exitReason) && mShouldUpdateRecents) {
- recentTasks.removeSplitPair(mMainStage.getTopVisibleChildTaskId());
- recentTasks.removeSplitPair(mSideStage.getTopVisibleChildTaskId());
- }
- });
mShouldUpdateRecents = false;
mIsDividerRemoteAnimating = false;
mSplitRequest = null;
@@ -1481,6 +1494,17 @@
}
}
+ private void clearSplitPairedInRecents(@ExitReason int exitReason) {
+ if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return;
+
+ mRecentTasks.ifPresent(recentTasks -> {
+ // Notify recents if we are exiting in a way that breaks the pair, and disable further
+ // updates to splits in the recents until we enter split again
+ mMainStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+ mSideStage.doForAllChildTasks(taskId -> recentTasks.removeSplitPair(taskId));
+ });
+ }
+
/**
* Unlike exitSplitScreen, this takes a stagetype vs an actual stage-reference and populates
* an existing WindowContainerTransaction (rather than applying immediately). This is intended
@@ -2208,7 +2232,11 @@
}
}
- void updateSurfaces(SurfaceControl.Transaction transaction) {
+ /**
+ * Update surfaces of the split screen layout based on the current state
+ * @param transaction to write the updates to
+ */
+ public void updateSurfaces(SurfaceControl.Transaction transaction) {
updateSurfaceBounds(mSplitLayout, transaction, /* applyResizingOffset */ false);
mSplitLayout.update(transaction);
}
@@ -2227,26 +2255,18 @@
@VisibleForTesting
void onFoldedStateChanged(boolean folded) {
- int topStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
+ mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
if (!folded) return;
- if (!mMainStage.isActive()) return;
+ if (!isSplitActive() || !isSplitScreenVisible()) return;
+ // To avoid split dismiss when user fold the device and unfold to use later, we only
+ // record the flag here and try to dismiss on wakeUp callback to ensure split dismiss
+ // when user interact on phone folded.
if (mMainStage.isFocused()) {
- topStageAfterFoldDismiss = STAGE_TYPE_MAIN;
+ mTopStageAfterFoldDismiss = STAGE_TYPE_MAIN;
} else if (mSideStage.isFocused()) {
- topStageAfterFoldDismiss = STAGE_TYPE_SIDE;
- }
-
- if (ENABLE_SHELL_TRANSITIONS) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- prepareExitSplitScreen(topStageAfterFoldDismiss, wct);
- mSplitTransitions.startDismissTransition(wct, this,
- topStageAfterFoldDismiss, EXIT_REASON_DEVICE_FOLDED);
- } else {
- exitSplitScreen(
- topStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
- EXIT_REASON_DEVICE_FOLDED);
+ mTopStageAfterFoldDismiss = STAGE_TYPE_SIDE;
}
}
@@ -2568,8 +2588,11 @@
// handling to the mixed-handler to deal with splitting it up.
if (mMixedHandler.animatePendingSplitWithDisplayChange(transition, info,
startTransaction, finishTransaction, finishCallback)) {
- mSplitLayout.update(startTransaction);
- startTransaction.apply();
+ if (mSplitTransitions.isPendingResize(transition)) {
+ // Only need to update in resize because divider exist before transition.
+ mSplitLayout.update(startTransaction);
+ startTransaction.apply();
+ }
return true;
}
}
@@ -2939,8 +2962,6 @@
mSideStage.getSplitDecorManager().release(callbackT);
callbackWct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, false);
});
-
- addDividerBarToTransition(info, false /* show */);
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index e2c55e4..af7bf36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -55,6 +55,7 @@
import java.io.PrintWriter;
import java.util.Optional;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -347,6 +348,13 @@
wct.reorder(mChildrenTaskInfo.get(taskId).token, onTop /* onTop */);
}
+ void doForAllChildTasks(Consumer<Integer> consumer) {
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
+ final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
+ consumer.accept(taskInfo.taskId);
+ }
+ }
+
/** Collects all the current child tasks and prepares transaction to evict them to display. */
void evictAllChildren(WindowContainerTransaction wct) {
for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index 944acb9..daf8be6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -189,15 +189,10 @@
if (taskView == null) return null;
// Opening types should all be initiated by shell
if (!TransitionUtil.isClosingType(request.getType())) return null;
- PendingTransition pending = findPendingCloseTransition(taskView);
- if (pending == null) {
- pending = new PendingTransition(request.getType(), null, taskView, null /* cookie */);
- }
- if (pending.mClaimed != null) {
- throw new IllegalStateException("Task is closing in 2 collecting transitions?"
- + " This state doesn't make sense");
- }
+ PendingTransition pending = new PendingTransition(request.getType(), null,
+ taskView, null /* cookie */);
pending.mClaimed = transition;
+ mPending.add(pending);
return new WindowContainerTransaction();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index d9edde1..c5c22de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -704,6 +704,9 @@
if (mPipHandler != null) {
mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction);
}
+ if (mSplitHandler != null && mSplitHandler.isSplitActive()) {
+ mSplitHandler.updateSurfaces(startTransaction);
+ }
return mUnfoldHandler.startAnimation(
mixed.mTransition, info, startTransaction, finishTransaction, finishCB);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index 21994a9..bb5d546 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -270,7 +270,6 @@
@Override
public void prepareStartTransaction(Transaction transaction) {
mUnfoldBackgroundController.ensureBackground(transaction);
- mSplitScreenController.get().get().updateSplitScreenSurfaces(transaction);
}
@Override
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 7245bc9..1a18fc2 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
@@ -24,9 +24,9 @@
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.DRAG_FREEFORM_SCALE;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION;
+import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -112,9 +112,8 @@
private SplitScreenController mSplitScreenController;
- private ValueAnimator mDragToDesktopValueAnimator;
+ private MoveToDesktopAnimator mMoveToDesktopAnimator;
private final Rect mDragToDesktopAnimationStartBounds = new Rect();
- private boolean mDragToDesktopAnimationStarted;
public DesktopModeWindowDecorViewModel(
Context context,
@@ -233,7 +232,6 @@
removeTaskFromEventReceiver(oldTaskInfo.displayId);
incrementEventReceiverTasks(taskInfo.displayId);
}
-
decoration.relayout(taskInfo);
}
@@ -599,7 +597,7 @@
}
case MotionEvent.ACTION_UP: {
if (relevantDecor == null) {
- mDragToDesktopAnimationStarted = false;
+ mMoveToDesktopAnimator = null;
mTransitionDragActive = false;
return;
}
@@ -613,14 +611,14 @@
} else if (DesktopModeStatus.isProto1Enabled()) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
}
- mDragToDesktopAnimationStarted = false;
+ mMoveToDesktopAnimator = null;
return;
- } else if (mDragToDesktopAnimationStarted) {
- Point position = new Point((int) ev.getX(), (int) ev.getY());
+ } else if (mMoveToDesktopAnimator != null) {
relevantDecor.incrementRelayoutBlock();
mDesktopTasksController.ifPresent(
- c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo, position));
- mDragToDesktopAnimationStarted = false;
+ c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo,
+ mMoveToDesktopAnimator));
+ mMoveToDesktopAnimator = null;
return;
}
}
@@ -640,21 +638,19 @@
final int statusBarHeight = getStatusBarHeight(
relevantDecor.mTaskInfo.displayId);
if (ev.getY() > statusBarHeight) {
- if (!mDragToDesktopAnimationStarted) {
- mDragToDesktopAnimationStarted = true;
+ if (mMoveToDesktopAnimator == null) {
+ mMoveToDesktopAnimator = new MoveToDesktopAnimator(
+ mDragToDesktopAnimationStartBounds, relevantDecor.mTaskInfo,
+ relevantDecor.mTaskSurface);
mDesktopTasksController.ifPresent(
c -> c.moveToFreeform(relevantDecor.mTaskInfo,
- mDragToDesktopAnimationStartBounds));
- startAnimation(relevantDecor);
+ mDragToDesktopAnimationStartBounds,
+ mMoveToDesktopAnimator));
+ mMoveToDesktopAnimator.startAnimation();
}
}
- if (mDragToDesktopAnimationStarted) {
- Transaction t = mTransactionFactory.get();
- float width = (float) mDragToDesktopValueAnimator.getAnimatedValue()
- * mDragToDesktopAnimationStartBounds.width();
- float x = ev.getX() - (width / 2);
- t.setPosition(relevantDecor.mTaskSurface, x, ev.getY());
- t.apply();
+ if (mMoveToDesktopAnimator != null) {
+ mMoveToDesktopAnimator.updatePosition(ev);
}
}
break;
@@ -662,7 +658,7 @@
case MotionEvent.ACTION_CANCEL: {
mTransitionDragActive = false;
- mDragToDesktopAnimationStarted = false;
+ mMoveToDesktopAnimator = null;
}
}
}
@@ -729,20 +725,6 @@
animator.start();
}
- private void startAnimation(@NonNull DesktopModeWindowDecoration focusedDecor) {
- mDragToDesktopValueAnimator = ValueAnimator.ofFloat(1f, DRAG_FREEFORM_SCALE);
- mDragToDesktopValueAnimator.setDuration(FREEFORM_ANIMATION_DURATION);
- final Transaction t = mTransactionFactory.get();
- mDragToDesktopValueAnimator.addUpdateListener(animation -> {
- final float animatorValue = (float) animation.getAnimatedValue();
- SurfaceControl sc = focusedDecor.mTaskSurface;
- t.setScale(sc, animatorValue, animatorValue);
- t.apply();
- });
-
- mDragToDesktopValueAnimator.start();
- }
-
@Nullable
private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
if (mSplitScreenController != null && mSplitScreenController.isSplitScreenVisible()) {
@@ -817,6 +799,7 @@
return DesktopModeStatus.isProto2Enabled()
&& taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
&& taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
+ && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop()
&& mDisplayController.getDisplayContext(taskInfo.displayId)
.getResources().getConfiguration().smallestScreenWidthDp >= 600;
}
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 336d95e..7c6fb99 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
@@ -336,6 +336,7 @@
private final Runnable mConsumeBatchEventRunnable;
private boolean mConsumeBatchEventScheduled;
private boolean mShouldHandleEvents;
+ private int mLastCursorType = PointerIcon.TYPE_DEFAULT;
private TaskResizeInputEventReceiver(
InputChannel inputChannel, Handler handler, Choreographer choreographer) {
@@ -437,7 +438,6 @@
break;
}
case MotionEvent.ACTION_HOVER_EXIT:
- mInputManager.setPointerIconType(PointerIcon.TYPE_DEFAULT);
result = true;
break;
}
@@ -477,7 +477,13 @@
if (y > mTaskHeight - mTaskCornerRadius) {
ctrlType |= CTRL_TYPE_BOTTOM;
}
- return checkDistanceFromCenter(ctrlType, x, y);
+ // Check distances from the center if it's in one of four corners.
+ if ((ctrlType & (CTRL_TYPE_LEFT | CTRL_TYPE_RIGHT)) != 0
+ && (ctrlType & (CTRL_TYPE_TOP | CTRL_TYPE_BOTTOM)) != 0) {
+ return checkDistanceFromCenter(ctrlType, x, y);
+ }
+ // Otherwise, we should make sure we don't resize tasks inside task bounds.
+ return (x < 0 || y < 0 || x >= mTaskWidth || y >= mTaskHeight) ? ctrlType : 0;
}
// If corner input is not within appropriate distance of corner radius, do not use it.
@@ -511,7 +517,8 @@
break;
}
default: {
- return ctrlType;
+ throw new IllegalArgumentException("ctrlType should be complex, but it's 0x"
+ + Integer.toHexString(ctrlType));
}
}
double distanceFromCenter = Math.hypot(x - centerX, y - centerY);
@@ -564,7 +571,19 @@
cursorType = PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW;
break;
}
- mInputManager.setPointerIconType(cursorType);
+ // Only update the cursor type to default once so that views behind the decor container
+ // layer that aren't in the active resizing regions have chances to update the cursor
+ // type. We would like to enforce the cursor type by setting the cursor type multilple
+ // times in active regions because we shouldn't allow the views behind to change it, as
+ // we'll pilfer the gesture initiated in this area. This is necessary because 1) we
+ // should allow the views behind regions only for touches to set the cursor type; and 2)
+ // there is a small region out of each rounded corner that's inside the task bounds,
+ // where views in the task can receive input events because we can't set touch regions
+ // of input sinks to have rounded corners.
+ if (mLastCursorType != cursorType || cursorType != PointerIcon.TYPE_DEFAULT) {
+ mInputManager.setPointerIconType(cursorType);
+ mLastCursorType = cursorType;
+ }
}
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt
new file mode 100644
index 0000000..b2267dd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MoveToDesktopAnimator.kt
@@ -0,0 +1,72 @@
+package com.android.wm.shell.windowdecor
+
+import android.animation.ValueAnimator
+import android.app.ActivityManager.RunningTaskInfo
+import android.graphics.PointF
+import android.graphics.Rect
+import android.view.MotionEvent
+import android.view.SurfaceControl
+
+/**
+ * Creates an animator to shrink and position task after a user drags a fullscreen task from
+ * the top of the screen to transition it into freeform and before the user releases the task. The
+ * MoveToDesktopAnimator object also holds information about the state of the task that are
+ * accessed by the EnterDesktopTaskTransitionHandler.
+ */
+class MoveToDesktopAnimator @JvmOverloads constructor(
+ private val startBounds: Rect,
+ private val taskInfo: RunningTaskInfo,
+ private val taskSurface: SurfaceControl,
+ private val transactionFactory: () -> SurfaceControl.Transaction =
+ SurfaceControl::Transaction
+) {
+ companion object {
+ // The size of the screen during drag relative to the fullscreen size
+ const val DRAG_FREEFORM_SCALE: Float = 0.4f
+ const val ANIMATION_DURATION = 336
+ }
+
+ private val animatedTaskWidth
+ get() = dragToDesktopAnimator.animatedValue as Float * startBounds.width()
+ private val dragToDesktopAnimator: ValueAnimator = ValueAnimator.ofFloat(1f,
+ DRAG_FREEFORM_SCALE)
+ .setDuration(ANIMATION_DURATION.toLong())
+ .apply {
+ val t = SurfaceControl.Transaction()
+ addUpdateListener { animation ->
+ val animatorValue = animation.animatedValue as Float
+ t.setScale(taskSurface, animatorValue, animatorValue)
+ .apply()
+ }
+ }
+
+ val taskId get() = taskInfo.taskId
+ val position: PointF = PointF(0.0f, 0.0f)
+
+ /**
+ * Starts the animation that scales the task down.
+ */
+ fun startAnimation() {
+ dragToDesktopAnimator.start()
+ }
+
+ /**
+ * Uses the position of the motion event and the current scale of the task as defined by the
+ * ValueAnimator to update the local position variable and set the task surface's position
+ */
+ fun updatePosition(ev: MotionEvent) {
+ position.x = ev.x - animatedTaskWidth / 2
+ position.y = ev.y
+
+ val t = transactionFactory()
+ t.setPosition(taskSurface, position.x, position.y)
+ t.apply()
+ }
+
+ /**
+ * Ends the animation, setting the scale and position to the final animation value
+ */
+ fun endAnimator() {
+ dragToDesktopAnimator.end()
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/Android.bp b/libs/WindowManager/Shell/tests/flicker/Android.bp
index 89747df..208ae84 100644
--- a/libs/WindowManager/Shell/tests/flicker/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/Android.bp
@@ -138,7 +138,7 @@
android_test {
name: "WMShellFlickerServiceTests",
defaults: ["WMShellFlickerTestsDefault"],
- additional_manifests: ["manifests/AndroidManifestSplitScreen.xml"],
+ additional_manifests: ["manifests/AndroidManifestService.xml"],
package_name: "com.android.wm.shell.flicker.service",
instrumentation_target_package: "com.android.wm.shell.flicker.service",
srcs: [
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
index 991d7b5..c8a9637 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTestTemplate.xml
@@ -93,6 +93,8 @@
value="/data/user/0/com.android.server.wm.flicker.pip/files"/>
<option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.splitscreen/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml
new file mode 100644
index 0000000..c7aca1a
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/manifests/AndroidManifestService.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.flicker.service">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.wm.shell.flicker.service"
+ android:label="WindowManager Flicker Service Tests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
index d3f3c5b..47a7e65 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
@@ -49,7 +49,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchLauncherToLetterboxAppTest(flicker: LegacyFlickerTest) :
+class QuickSwitchLauncherToLetterboxAppTest(flicker: LegacyFlickerTest) :
BaseAppCompat(flicker) {
/** {@inheritDoc} */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
index bc565bc..f165cb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
@@ -22,7 +22,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
@@ -40,11 +39,10 @@
* Switch in different bubble notifications
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FlakyTest(bugId = 217777115)
-open class ChangeActiveActivityFromBubbleTest(flicker: LegacyFlickerTest) :
+class ChangeActiveActivityFromBubbleTest(flicker: LegacyFlickerTest) :
BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt
deleted file mode 100644
index abc6b9f..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTestCfArm.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.bubble
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class ChangeActiveActivityFromBubbleTestCfArm(flicker: LegacyFlickerTest) :
- ChangeActiveActivityFromBubbleTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
index 3f28ae8..9ca7bf1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
@@ -20,12 +20,12 @@
import android.graphics.Point
import android.platform.test.annotations.Presubmit
import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.util.DisplayMetrics
import android.view.WindowManager
-import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Test
@@ -42,10 +42,9 @@
* Dismiss a bubble notification
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class DragToDismissBubbleScreenTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
+class DragToDismissBubbleScreenTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
private val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
private val displaySize = DisplayMetrics()
@@ -80,7 +79,8 @@
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
flicker.assertLayers {
this.visibleLayersShownMoreThanOneConsecutiveEntry(
- LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS + listOf(testApp)
+ LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
+ listOf(testApp, ComponentNameMatcher(className = "Bubbles!#"))
)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt
deleted file mode 100644
index ee55eca..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTestCfArm.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.bubble
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class DragToDismissBubbleScreenTestCfArm(flicker: LegacyFlickerTest) :
- DragToDismissBubbleScreenTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
index 5085394..4959672 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
@@ -20,7 +20,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Test
@@ -39,10 +38,9 @@
* The activity for the bubble is launched
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class OpenActivityFromBubbleTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
+class OpenActivityFromBubbleTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt
deleted file mode 100644
index 6a46d23..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTestCfArm.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.bubble
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class OpenActivityFromBubbleTestCfArm(flicker: LegacyFlickerTest) :
- OpenActivityFromBubbleTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
index a926bb7..0d95574 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
@@ -20,7 +20,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.junit.Test
@@ -38,10 +37,9 @@
* Send a bubble notification
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class SendBubbleNotificationTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
+class SendBubbleNotificationTest(flicker: LegacyFlickerTest) : BaseBubbleScreen(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt
deleted file mode 100644
index a401cb4..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTestCfArm.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.bubble
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class SendBubbleNotificationTestCfArm(flicker: LegacyFlickerTest) :
- SendBubbleNotificationTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index 68bc9a2..ca28f52 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -21,7 +21,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,11 +48,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
+class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions {
val pipRegion = wmHelper.getWindowRegion(pipApp).bounds
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt
deleted file mode 100644
index 7a66889..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ClosePipBySwipingDownTestCfArm(flicker: LegacyFlickerTest) :
- ClosePipBySwipingDownTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
- * orientation and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index dc48696..4da628c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -20,7 +20,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -49,11 +48,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
+class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.closePipWindow(wmHelper) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt
deleted file mode 100644
index 718b14b..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ClosePipWithDismissButtonTestCfArm(flicker: LegacyFlickerTest) :
- ClosePipWithDismissButtonTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
- * orientation and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 5e39262..e0b18de 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -20,7 +20,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
@@ -40,11 +39,10 @@
* Press Home button or swipe up to go Home and put [pipApp] in pip mode
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
+class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
override val defaultEnterPip: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
deleted file mode 100644
index 2b3e76a..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTestCfArm.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/** This test will fail because of b/264261596 */
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipOnUserLeaveHintTestCfArm(flicker: LegacyFlickerTest) :
- EnterPipOnUserLeaveHintTest(flicker)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index ec35837..c003da6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -28,7 +28,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
@@ -65,11 +64,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = FixedOrientationAppHelper(instrumentation)
private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90)
private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt
deleted file mode 100644
index 9264219..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationCfArm.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/** This test fails because of b/264261596 */
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipToOtherOrientationCfArm(flicker: LegacyFlickerTest) :
- EnterPipToOtherOrientation(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index 76c811c..f9efffe 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -19,7 +19,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -46,7 +45,6 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt
deleted file mode 100644
index 78e8049..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipViaAppUiButtonTestCfArm(flicker: LegacyFlickerTest) :
- EnterPipViaAppUiButtonTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
- * orientation and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index b80b748..c4e63c3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -19,7 +19,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -48,11 +47,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) :
+class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) :
ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt
deleted file mode 100644
index e25c0d6..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipToAppViaExpandButtonTestCfArm(flicker: LegacyFlickerTest) :
- ExitPipToAppViaExpandButtonTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index f003ed8..839bbd4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -19,7 +19,6 @@
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -47,11 +46,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) {
+class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
setup {
// launch an app behind the pip one
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt
deleted file mode 100644
index be19f3c..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipToAppViaIntentTestCfArm(flicker: LegacyFlickerTest) :
- ExitPipToAppViaIntentTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
- * orientation and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index a1d3a11..ea67e3d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,11 +50,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExpandPipOnDoubleClickTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+class ExpandPipOnDoubleClickTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.doubleClickPipWindow(wmHelper) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt
deleted file mode 100644
index 3095cac..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTestTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnDoubleClickTestTestCfArm(flicker: LegacyFlickerTest) :
- ExpandPipOnDoubleClickTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 8c8d280..0f30cef 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -22,7 +22,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -30,11 +29,10 @@
import org.junit.runners.Parameterized
/** Test expanding a pip window via pinch out gesture. */
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ExpandPipOnPinchOpenTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+class ExpandPipOnPinchOpenTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
override val thisTransition: FlickerBuilder.() -> Unit = {
transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.25f, 30) }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt
deleted file mode 100644
index 1a1ce68..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnPinchOpenTestCfArm(flicker: LegacyFlickerTest) :
- ExpandPipOnPinchOpenTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index dffc822..c10860a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -25,7 +25,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
@@ -35,11 +34,10 @@
import org.junit.runners.Parameterized
/** Test Pip launch. To run this test: `atest WMShellFlickerTests:PipKeyboardTest` */
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class MovePipOnImeVisibilityChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+class MovePipOnImeVisibilityChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val imeApp = ImeAppHelper(instrumentation)
override val thisTransition: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt
deleted file mode 100644
index 63292a4..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTestCfArm.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MovePipOnImeVisibilityChangeTestCfArm(flicker: LegacyFlickerTest) :
- MovePipOnImeVisibilityChangeTest(flicker) {
- companion object {
- private const val TAG_IME_VISIBLE = "imeIsVisible"
-
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index 0ff9cff..e588f87 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.WindowUtils
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
@@ -55,11 +54,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowPipAndRotateDisplay(flicker: LegacyFlickerTest) : PipTransition(flicker) {
+class ShowPipAndRotateDisplay(flicker: LegacyFlickerTest) : PipTransition(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
private val screenBoundsEnd = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt
deleted file mode 100644
index 2516471..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplayCfArm.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.flicker.pip
-
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowPipAndRotateDisplayCfArm(flicker: LegacyFlickerTest) : ShowPipAndRotateDisplay(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring repetitions, screen
- * orientation and navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): Collection<FlickerTest> {
- return LegacyFlickerTestFactory.rotationTests()
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt
new file mode 100644
index 0000000..610cede
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/Utils.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.service
+
+import android.app.Instrumentation
+import android.platform.test.rule.NavigationModeRule
+import android.platform.test.rule.PressHomeRule
+import android.platform.test.rule.UnlockScreenRule
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.apphelpers.MessagingAppHelper
+import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.device.flicker.rules.LaunchAppRule
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.rules.RuleChain
+
+object Utils {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ fun testSetupRule(navigationMode: NavBar, rotation: Rotation): RuleChain {
+ return RuleChain.outerRule(UnlockScreenRule())
+ .around(
+ NavigationModeRule(navigationMode.value, /* changeNavigationModeAfterTest */ false)
+ )
+ .around(
+ LaunchAppRule(MessagingAppHelper(instrumentation), clearCacheAfterParsing = false)
+ )
+ .around(RemoveAllTasksButHomeRule())
+ .around(
+ ChangeDisplayOrientationRule(
+ rotation,
+ resetOrientationAfterTest = false,
+ clearCacheAfterParsing = false
+ )
+ )
+ .around(PressHomeRule())
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS
new file mode 100644
index 0000000..3ab6a1e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/OWNERS
@@ -0,0 +1,2 @@
+# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > WM Shell > Split Screen
+# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
index 76ad6b9..5bfc889 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -42,9 +43,7 @@
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
private val textEditApp = SplitScreenUtils.getIme(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
index 25182b4..d07daff 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
index 000b628..d428dea 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
index dd9ff3c..dc2a6ac 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
index 4bbb9aa..677aeb07 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
index a2b7526..f4f6878 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -41,9 +42,7 @@
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
private val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
index 1ccd813..36a458f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Assume
import org.junit.Before
@@ -41,9 +42,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
index 664786b..322f711 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
index 88fd084..f164451 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SplitScreenUtils.kt
index 83a18e8..3831c65 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SplitScreenUtils.kt
@@ -19,25 +19,15 @@
import android.app.Instrumentation
import android.graphics.Point
import android.os.SystemClock
-import android.platform.test.rule.NavigationModeRule
-import android.platform.test.rule.PressHomeRule
-import android.platform.test.rule.UnlockScreenRule
-import android.tools.common.NavBar
-import android.tools.common.Rotation
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.traces.component.IComponentMatcher
import android.tools.common.traces.component.IComponentNameMatcher
-import android.tools.device.apphelpers.MessagingAppHelper
import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.flicker.rules.LaunchAppRule
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import android.tools.device.traces.parsers.WindowManagerStateHelper
import android.tools.device.traces.parsers.toFlickerComponent
import android.view.InputDevice
import android.view.MotionEvent
import android.view.ViewConfiguration
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.UiDevice
@@ -52,7 +42,6 @@
import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
import org.junit.Assert.assertNotNull
-import org.junit.rules.RuleChain
object SplitScreenUtils {
private const val TIMEOUT_MS = 3_000L
@@ -73,30 +62,6 @@
private val overviewSnapshotSelector: BySelector
get() = By.res(LAUNCHER_UI_PACKAGE_NAME, OVERVIEW_SNAPSHOT)
- private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
-
- fun testSetupRule(navigationMode: () -> NavBar, rotation: () -> Rotation): RuleChain {
- return RuleChain.outerRule(UnlockScreenRule())
- .around(
- NavigationModeRule(
- navigationMode().value,
- /* changeNavigationModeAfterTest */ false
- )
- )
- .around(
- LaunchAppRule(MessagingAppHelper(instrumentation), clearCacheAfterParsing = false)
- )
- .around(RemoveAllTasksButHomeRule())
- .around(
- ChangeDisplayOrientationRule(
- rotation(),
- resetOrientationAfterTest = false,
- clearCacheAfterParsing = false
- )
- )
- .around(PressHomeRule())
- }
-
fun getPrimary(instrumentation: Instrumentation): StandardAppHelper =
SimpleAppHelper(
instrumentation,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
index e5501f4..805d987 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
@@ -25,6 +25,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -42,9 +43,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
index b3f1e87..4229ebb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -41,9 +42,7 @@
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
private val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
index d112116..f2d56b9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
index 9ab924c..d44d177 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,9 +41,7 @@
private val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
private val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
index b694dfa..e2c6ca6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -42,9 +43,7 @@
private val thirdApp = SplitScreenUtils.getIme(instrumentation)
private val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
- @Rule
- @JvmField
- val testSetupRule = SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { rotation })
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
index f78b788..df98d8f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
@@ -23,6 +23,7 @@
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.wm.shell.flicker.service.Utils
import org.junit.After
import org.junit.Before
import org.junit.Ignore
@@ -40,8 +41,7 @@
@Rule
@JvmField
- val testSetupRule =
- SplitScreenUtils.testSetupRule({ NavBar.MODE_GESTURAL }, { Rotation.ROTATION_0 })
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
@Before
fun setup() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS
new file mode 100644
index 0000000..3ab6a1e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/OWNERS
@@ -0,0 +1,2 @@
+# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > WM Shell > Split Screen
+# Bug component: 928697
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index d3434a5..3064bd7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -43,11 +43,4 @@
secondaryApp.exit(wmHelper)
}
}
-
- protected open val withoutTracing: FlickerBuilder.() -> Unit = {
- withoutLayerTracing()
- withoutWindowManagerTracing()
- withoutTransitionTracing()
- withoutTransactionsTracing()
- }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
index 8592dea..c6642f3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
@@ -28,6 +28,7 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
@@ -41,6 +42,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.MoveToDesktopAnimator;
import junit.framework.AssertionFailedError;
@@ -73,6 +75,10 @@
ShellExecutor mExecutor;
@Mock
SurfaceControl mSurfaceControl;
+ @Mock
+ MoveToDesktopAnimator mMoveToDesktopAnimator;
+ @Mock
+ PointF mPosition;
private EnterDesktopTaskTransitionHandler mEnterDesktopTaskTransitionHandler;
@@ -82,6 +88,7 @@
doReturn(mExecutor).when(mTransitions).getMainExecutor();
doReturn(mAnimationT).when(mTransactionFactory).get();
+ doReturn(mPosition).when(mMoveToDesktopAnimator).getPosition();
mEnterDesktopTaskTransitionHandler = new EnterDesktopTaskTransitionHandler(mTransitions,
mTransactionFactory);
@@ -89,12 +96,15 @@
@Test
public void testEnterFreeformAnimation() {
- final int transitionType = Transitions.TRANSIT_ENTER_FREEFORM;
final int taskId = 1;
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
- .startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
+ .startTransition(Transitions.TRANSIT_ENTER_FREEFORM, wct,
+ mEnterDesktopTaskTransitionHandler);
+ doReturn(taskId).when(mMoveToDesktopAnimator).getTaskId();
+
+ mEnterDesktopTaskTransitionHandler.startMoveToFreeformAnimation(wct,
+ mMoveToDesktopAnimator, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 7c1da35..527dc01 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -133,8 +133,7 @@
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0);
- mPolicy = spy(new DragAndDropPolicy(
- mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter));
+ mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mSplitScreenStarter));
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
setClipDataResizeable(mNonResizeableActivityClipData, false);
@@ -206,7 +205,10 @@
@Test
public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() {
setRunningTask(mHomeTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mLandscapeDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
@@ -218,7 +220,10 @@
@Test
public void testDragAppOverFullscreenApp_expectSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mLandscapeDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
@@ -235,7 +240,10 @@
@Test
public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mPortraitDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mPortraitDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = assertExactTargetTypes(
mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
@@ -252,7 +260,10 @@
@Test
public void testTargetHitRects() {
setRunningTask(mFullscreenAppTask);
- mPolicy.start(mLandscapeDisplayLayout, mActivityClipData, mLoggerSessionId);
+ DragSession dragSession = new DragSession(mContext, mActivityTaskManager,
+ mLandscapeDisplayLayout, mActivityClipData);
+ dragSession.update();
+ mPolicy.start(dragSession, mLoggerSessionId);
ArrayList<Target> targets = mPolicy.getTargets(mInsets);
for (Target t : targets) {
assertTrue(mPolicy.getTargetAtLocation(t.hitRegion.left, t.hitRegion.top) == t);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
index 1379aed..528c23c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
@@ -110,17 +110,17 @@
sExpectedDefaultSizes.put(16f / 9, new Size(600, 338));
sExpectedMinSizes.put(16f / 9, new Size(501, 282));
- sExpectedMaxSizes.put(4f / 3, new Size(892, 669));
- sExpectedDefaultSizes.put(4f / 3, new Size(535, 401));
+ sExpectedMaxSizes.put(4f / 3, new Size(893, 670));
+ sExpectedDefaultSizes.put(4f / 3, new Size(536, 402));
sExpectedMinSizes.put(4f / 3, new Size(447, 335));
- sExpectedMaxSizes.put(3f / 4, new Size(669, 892));
- sExpectedDefaultSizes.put(3f / 4, new Size(401, 535));
+ sExpectedMaxSizes.put(3f / 4, new Size(670, 893));
+ sExpectedDefaultSizes.put(3f / 4, new Size(402, 536));
sExpectedMinSizes.put(3f / 4, new Size(335, 447));
- sExpectedMaxSizes.put(9f / 16, new Size(562, 999));
- sExpectedDefaultSizes.put(9f / 16, new Size(337, 599));
- sExpectedMinSizes.put(9f / 16, new Size(281, 500));
+ sExpectedMaxSizes.put(9f / 16, new Size(563, 1001));
+ sExpectedDefaultSizes.put(9f / 16, new Size(338, 601));
+ sExpectedMinSizes.put(9f / 16, new Size(282, 501));
}
private void forEveryTestCaseCheck(Map<Float, Size> expectedSizes,
@@ -192,7 +192,7 @@
// an initial size with 16:9 aspect ratio
Size initSize = new Size(600, 337);
- Size expectedSize = new Size(337, 599);
+ Size expectedSize = new Size(338, 601);
Size actualSize = mPipSizeSpecHandler.getSizeForAspectRatio(initSize, 9f / 16);
Assert.assertEquals(expectedSize, actualSize);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index e59d09c..cc4db22 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -347,13 +347,20 @@
}
@Test
- public void testExitSplitScreenAfterFolded() {
- when(mMainStage.isActive()).thenReturn(true);
+ public void testExitSplitScreenAfterFoldedAndWakeUp() {
when(mMainStage.isFocused()).thenReturn(true);
when(mMainStage.getTopVisibleChildTaskId()).thenReturn(INVALID_TASK_ID);
+ mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().setVisible(true).build();
+ mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().setVisible(true).build();
+ when(mStageCoordinator.isSplitActive()).thenReturn(true);
+ when(mStageCoordinator.isSplitScreenVisible()).thenReturn(true);
mStageCoordinator.onFoldedStateChanged(true);
+ assertEquals(mStageCoordinator.mTopStageAfterFoldDismiss, STAGE_TYPE_MAIN);
+
+ mStageCoordinator.onFinishedWakingUp();
+
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
verify(mTaskOrganizer).startNewTransition(eq(TRANSIT_SPLIT_DISMISS), notNull());
} else {
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 52e7a70..d7b5914 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -40,17 +40,24 @@
public:
ZipEntry entry;
std::string_view name;
- void *cookie;
+ void *cookie = nullptr;
- _ZipEntryRO() : cookie(NULL) {}
+ _ZipEntryRO() = default;
~_ZipEntryRO() {
- EndIteration(cookie);
+ EndIteration(cookie);
+ }
+
+ android::ZipEntryRO convertToPtr() {
+ _ZipEntryRO* result = new _ZipEntryRO;
+ result->entry = std::move(this->entry);
+ result->name = std::move(this->name);
+ result->cookie = std::exchange(this->cookie, nullptr);
+ return result;
}
private:
- _ZipEntryRO(const _ZipEntryRO& other);
- _ZipEntryRO& operator=(const _ZipEntryRO& other);
+ DISALLOW_COPY_AND_ASSIGN(_ZipEntryRO);
};
ZipFileRO::~ZipFileRO() {
@@ -94,17 +101,15 @@
ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const
{
- _ZipEntryRO* data = new _ZipEntryRO;
+ _ZipEntryRO data;
+ data.name = entryName;
- data->name = entryName;
-
- const int32_t error = FindEntry(mHandle, entryName, &(data->entry));
+ const int32_t error = FindEntry(mHandle, entryName, &(data.entry));
if (error) {
- delete data;
- return NULL;
+ return nullptr;
}
- return (ZipEntryRO) data;
+ return data.convertToPtr();
}
/*
@@ -143,35 +148,50 @@
}
bool ZipFileRO::startIteration(void** cookie) {
- return startIteration(cookie, NULL, NULL);
+ return startIteration(cookie, nullptr, nullptr);
}
-bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix)
-{
- _ZipEntryRO* ze = new _ZipEntryRO;
- int32_t error = StartIteration(mHandle, &(ze->cookie),
+bool ZipFileRO::startIteration(void** cookie, const char* prefix, const char* suffix) {
+ auto result = startIterationOrError(prefix, suffix);
+ if (!result.ok()) {
+ return false;
+ }
+ *cookie = result.value();
+ return true;
+}
+
+base::expected<void*, int32_t>
+ZipFileRO::startIterationOrError(const char* prefix, const char* suffix) {
+ _ZipEntryRO ze;
+ int32_t error = StartIteration(mHandle, &(ze.cookie),
prefix ? prefix : "", suffix ? suffix : "");
if (error) {
ALOGW("Could not start iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
ErrorCodeString(error));
- delete ze;
- return false;
+ return base::unexpected(error);
}
- *cookie = ze;
- return true;
+ return ze.convertToPtr();
}
-ZipEntryRO ZipFileRO::nextEntry(void* cookie)
-{
+ZipEntryRO ZipFileRO::nextEntry(void* cookie) {
+ auto result = nextEntryOrError(cookie);
+ if (!result.ok()) {
+ return nullptr;
+ }
+ return result.value();
+}
+
+base::expected<ZipEntryRO, int32_t> ZipFileRO::nextEntryOrError(void* cookie) {
_ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie);
int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name));
if (error) {
if (error != -1) {
ALOGW("Error iteration over %s: %s", mFileName != NULL ? mFileName : "<null>",
ErrorCodeString(error));
+ return base::unexpected(error);
}
- return NULL;
+ return nullptr;
}
return &(ze->entry);
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index 10f6d06..be1f98f 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -37,6 +37,8 @@
#include <unistd.h>
#include <time.h>
+#include <android-base/expected.h>
+
#include <util/map_ptr.h>
#include <utils/Compat.h>
@@ -102,6 +104,11 @@
*/
bool startIteration(void** cookie);
bool startIteration(void** cookie, const char* prefix, const char* suffix);
+ /*
+ * Same as above, but returns the error code in case of failure.
+ * #see libziparchive/zip_error.h.
+ */
+ base::expected<void*, int32_t> startIterationOrError(const char* prefix, const char* suffix);
/**
* Return the next entry in iteration order, or NULL if there are no more
@@ -109,6 +116,12 @@
*/
ZipEntryRO nextEntry(void* cookie);
+ /**
+ * Same as above, but returns the error code in case of failure.
+ * #see libziparchive/zip_error.h.
+ */
+ base::expected<ZipEntryRO, int32_t> nextEntryOrError(void* cookie);
+
void endIteration(void* cookie);
void releaseEntry(ZipEntryRO entry) const;
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
index 26efb55..4736030 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
@@ -111,8 +111,14 @@
}
animator.addListener(listener)
continuation.invokeOnCancellation {
- animator.removeListener(listener)
- animator.cancel()
+ try {
+ animator.removeListener(listener)
+ animator.cancel()
+ } catch (exception: IndexOutOfBoundsException) {
+ // TODO(b/285666217): remove this try/catch once a proper fix is implemented.
+ // Cancelling the animator can cause an exception since we may be removing a
+ // listener during the cancellation. See b/285666217 for more details.
+ }
}
}
}
diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp
index 4c9a23d..740988f 100644
--- a/libs/hwui/jni/BitmapRegionDecoder.cpp
+++ b/libs/hwui/jni/BitmapRegionDecoder.cpp
@@ -90,8 +90,8 @@
requireUnpremul, prefColorSpace);
}
- bool decodeGainmapRegion(sp<uirenderer::Gainmap>* outGainmap, const SkIRect& desiredSubset,
- int sampleSize, bool requireUnpremul) {
+ bool decodeGainmapRegion(sp<uirenderer::Gainmap>* outGainmap, int outWidth, int outHeight,
+ const SkIRect& desiredSubset, int sampleSize, bool requireUnpremul) {
SkColorType decodeColorType = mGainmapBRD->computeOutputColorType(kN32_SkColorType);
sk_sp<SkColorSpace> decodeColorSpace =
mGainmapBRD->computeOutputColorSpace(decodeColorType, nullptr);
@@ -109,9 +109,8 @@
// kPremul_SkAlphaType is used just as a placeholder as it doesn't change the underlying
// allocation type. RecyclingClippingPixelAllocator will populate this with the
// actual alpha type in either allocPixelRef() or copyIfNecessary()
- sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(
- SkImageInfo::Make(desiredSubset.width(), desiredSubset.height(), decodeColorType,
- kPremul_SkAlphaType, decodeColorSpace));
+ sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(SkImageInfo::Make(
+ outWidth, outHeight, decodeColorType, kPremul_SkAlphaType, decodeColorSpace));
if (!nativeBitmap) {
ALOGE("OOM allocating Bitmap for Gainmap");
return false;
@@ -134,9 +133,12 @@
return true;
}
- SkIRect calculateGainmapRegion(const SkIRect& mainImageRegion) {
+ SkIRect calculateGainmapRegion(const SkIRect& mainImageRegion, int* inOutWidth,
+ int* inOutHeight) {
const float scaleX = ((float)mGainmapBRD->width()) / mMainImageBRD->width();
const float scaleY = ((float)mGainmapBRD->height()) / mMainImageBRD->height();
+ *inOutWidth *= scaleX;
+ *inOutHeight *= scaleY;
// TODO: Account for rounding error?
return SkIRect::MakeLTRB(mainImageRegion.left() * scaleX, mainImageRegion.top() * scaleY,
mainImageRegion.right() * scaleX,
@@ -328,21 +330,16 @@
sp<uirenderer::Gainmap> gainmap;
bool hasGainmap = brd->hasGainmap();
if (hasGainmap) {
- SkIRect adjustedSubset{};
+ int gainmapWidth = bitmap.width();
+ int gainmapHeight = bitmap.height();
if (javaBitmap) {
- // Clamp to the width/height of the recycled bitmap in case the reused bitmap
- // was too small for the specified rectangle, in which case we need to clip
- adjustedSubset = SkIRect::MakeXYWH(inputX, inputY,
- std::min(subset.width(), recycledBitmap->width()),
- std::min(subset.height(), recycledBitmap->height()));
- } else {
- // We are not recycling, so use the decoded width/height for calculating the gainmap
- // subset instead to ensure the gainmap region proportionally matches
- adjustedSubset = SkIRect::MakeXYWH(std::max(0, inputX), std::max(0, inputY),
- bitmap.width(), bitmap.height());
+ // If we are recycling we must match the inBitmap's relative dimensions
+ gainmapWidth = recycledBitmap->width();
+ gainmapHeight = recycledBitmap->height();
}
- SkIRect gainmapSubset = brd->calculateGainmapRegion(adjustedSubset);
- if (!brd->decodeGainmapRegion(&gainmap, gainmapSubset, sampleSize, requireUnpremul)) {
+ SkIRect gainmapSubset = brd->calculateGainmapRegion(subset, &gainmapWidth, &gainmapHeight);
+ if (!brd->decodeGainmapRegion(&gainmap, gainmapWidth, gainmapHeight, gainmapSubset,
+ sampleSize, requireUnpremul)) {
// If there is an error decoding Gainmap - we don't fail. We just don't provide Gainmap
hasGainmap = false;
}
diff --git a/libs/input/OWNERS b/libs/input/OWNERS
index d701f23..4c20c4d 100644
--- a/libs/input/OWNERS
+++ b/libs/input/OWNERS
@@ -1 +1 @@
-include /core/java/android/hardware/input/OWNERS
+include /INPUT_OWNERS
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index 0bc5a60..a77c943 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -55,15 +55,23 @@
private static final String KEY_GROUP_ROUTE = "androidx.mediarouter.media.KEY_GROUP_ROUTE";
private static final String KEY_VOLUME_HANDLING = "volumeHandling";
+ @NonNull
final String mId;
+ @Nullable
final CharSequence mName;
+ @Nullable
final String mOwnerPackageName;
+ @NonNull
final String mClientPackageName;
@Nullable
final String mProviderId;
+ @NonNull
final List<String> mSelectedRoutes;
+ @NonNull
final List<String> mSelectableRoutes;
+ @NonNull
final List<String> mDeselectableRoutes;
+ @NonNull
final List<String> mTransferableRoutes;
final int mVolumeHandling;
@@ -134,7 +142,9 @@
mIsSystemSession = src.readBoolean();
}
- private static Bundle updateVolumeHandlingInHints(Bundle controlHints, int volumeHandling) {
+ @Nullable
+ private static Bundle updateVolumeHandlingInHints(@Nullable Bundle controlHints,
+ int volumeHandling) {
// Workaround to preserve retro-compatibility with androidx.
// See b/228021646 for more details.
if (controlHints != null && controlHints.containsKey(KEY_GROUP_ROUTE)) {
@@ -167,11 +177,13 @@
return volumeHandling;
}
- private static String ensureString(String str) {
+ @NonNull
+ private static String ensureString(@Nullable String str) {
return str != null ? str : "";
}
- private static <T> List<T> ensureList(List<? extends T> list) {
+ @NonNull
+ private static <T> List<T> ensureList(@Nullable List<? extends T> list) {
if (list != null) {
return Collections.unmodifiableList(list);
}
@@ -370,11 +382,15 @@
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
+ if (obj == null) {
+ return false;
+ }
+
if (this == obj) {
return true;
}
- if (!(obj instanceof RoutingSessionInfo)) {
+ if (getClass() != obj.getClass()) {
return false;
}
@@ -454,21 +470,30 @@
* Builder class for {@link RoutingSessionInfo}.
*/
public static final class Builder {
- // TODO: Reorder these (important ones first)
- final String mId;
- CharSequence mName;
- String mOwnerPackageName;
- String mClientPackageName;
- String mProviderId;
- final List<String> mSelectedRoutes;
- final List<String> mSelectableRoutes;
- final List<String> mDeselectableRoutes;
- final List<String> mTransferableRoutes;
- int mVolumeHandling = MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
- int mVolumeMax;
- int mVolume;
- Bundle mControlHints;
- boolean mIsSystemSession;
+ @NonNull
+ private final String mId;
+ @Nullable
+ private CharSequence mName;
+ @Nullable
+ private String mOwnerPackageName;
+ @NonNull
+ private String mClientPackageName;
+ @Nullable
+ private String mProviderId;
+ @NonNull
+ private final List<String> mSelectedRoutes;
+ @NonNull
+ private final List<String> mSelectableRoutes;
+ @NonNull
+ private final List<String> mDeselectableRoutes;
+ @NonNull
+ private final List<String> mTransferableRoutes;
+ private int mVolumeHandling = MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
+ private int mVolumeMax;
+ private int mVolume;
+ @Nullable
+ private Bundle mControlHints;
+ private boolean mIsSystemSession;
/**
* Constructor for builder to create {@link RoutingSessionInfo}.
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index f3dfeb6..2795cfe 100644
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -455,11 +455,13 @@
* a number of consecutive 8-bit (unsigned) mono PCM samples equal to the capture size returned
* by {@link #getCaptureSize()}.
* <p>This method must be called when the Visualizer is enabled.
- * @param waveform array of bytes where the waveform should be returned
+ * @param waveform array of bytes where the waveform should be returned, array length must be
+ * at least equals to the capture size returned by {@link #getCaptureSize()}.
* @return {@link #SUCCESS} in case of success,
* {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
* in case of failure.
* @throws IllegalStateException
+ * @throws IllegalArgumentException
*/
public int getWaveForm(byte[] waveform)
throws IllegalStateException {
@@ -467,6 +469,12 @@
if (mState != STATE_ENABLED) {
throw(new IllegalStateException("getWaveForm() called in wrong state: "+mState));
}
+ int captureSize = getCaptureSize();
+ if (captureSize > waveform.length) {
+ throw(new IllegalArgumentException("getWaveForm() called with illegal size: "
+ + waveform.length + " expecting at least "
+ + captureSize + " bytes"));
+ }
return native_getWaveForm(waveform);
}
}
diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS
index 2273f81..cc9be9c 100644
--- a/media/java/android/media/projection/OWNERS
+++ b/media/java/android/media/projection/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1345447
+
michaelwr@google.com
santoscordon@google.com
chaviw@google.com
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
index b100980..fcc4ec1 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
@@ -31,9 +31,11 @@
import android.webkit.WebView;
import android.webkit.WebViewClient;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.phone.slice.SlicePurchaseController;
import java.net.URL;
+import java.util.Base64;
/**
* Activity that launches when the user clicks on the performance boost notification.
@@ -56,11 +58,17 @@
public class SlicePurchaseActivity extends Activity {
private static final String TAG = "SlicePurchaseActivity";
+ private static final int CONTENTS_TYPE_UNSPECIFIED = 0;
+ private static final int CONTENTS_TYPE_JSON = 1;
+ private static final int CONTENTS_TYPE_XML = 2;
+
@NonNull private WebView mWebView;
@NonNull private Context mApplicationContext;
@NonNull private Intent mIntent;
@NonNull private URL mUrl;
@TelephonyManager.PremiumCapability protected int mCapability;
+ @Nullable private String mUserData;
+ private int mContentsType;
private boolean mIsUserTriggeredFinish;
@Override
@@ -72,6 +80,7 @@
mCapability = mIntent.getIntExtra(SlicePurchaseController.EXTRA_PREMIUM_CAPABILITY,
SlicePurchaseController.PREMIUM_CAPABILITY_INVALID);
String url = mIntent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL);
+ mUserData = mIntent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA);
mApplicationContext = getApplicationContext();
mIsUserTriggeredFinish = true;
logd("onCreate: subId=" + subId + ", capability="
@@ -81,7 +90,17 @@
SlicePurchaseBroadcastReceiver.cancelNotification(mApplicationContext, mCapability);
// Verify purchase URL is valid
- mUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url);
+ String contentsType = mIntent.getStringExtra(SlicePurchaseController.EXTRA_CONTENTS_TYPE);
+ mContentsType = CONTENTS_TYPE_UNSPECIFIED;
+ if (!TextUtils.isEmpty(contentsType)) {
+ if (contentsType.equals("json")) {
+ mContentsType = CONTENTS_TYPE_JSON;
+ } else if (contentsType.equals("xml")) {
+ mContentsType = CONTENTS_TYPE_XML;
+ }
+ }
+ mUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url, mUserData,
+ mContentsType == CONTENTS_TYPE_UNSPECIFIED);
if (mUrl == null) {
String error = "Unable to create a purchase URL.";
loge(error);
@@ -95,6 +114,20 @@
return;
}
+ // Verify user data exists if contents type is specified
+ if (mContentsType != CONTENTS_TYPE_UNSPECIFIED && TextUtils.isEmpty(mUserData)) {
+ String error = "Contents type was specified but user data does not exist.";
+ loge(error);
+ Intent data = new Intent();
+ data.putExtra(SlicePurchaseController.EXTRA_FAILURE_CODE,
+ SlicePurchaseController.FAILURE_CODE_NO_USER_DATA);
+ data.putExtra(SlicePurchaseController.EXTRA_FAILURE_REASON, error);
+ SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponseWithData(mApplicationContext,
+ mIntent, SlicePurchaseController.EXTRA_INTENT_CARRIER_ERROR, data);
+ finishAndRemoveTask();
+ return;
+ }
+
// Verify intent is valid
if (!SlicePurchaseBroadcastReceiver.isIntentValid(mIntent)) {
loge("Not starting SlicePurchaseActivity with an invalid Intent: " + mIntent);
@@ -115,9 +148,7 @@
}
// Clear any cookies that might be persisted from previous sessions before loading WebView
- CookieManager.getInstance().removeAllCookies(value -> {
- setupWebView();
- });
+ CookieManager.getInstance().removeAllCookies(value -> setupWebView());
}
protected void onPurchaseSuccessful() {
@@ -190,14 +221,46 @@
// Display WebView
setContentView(mWebView);
- // Load the URL
- String userData = mIntent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA);
- if (TextUtils.isEmpty(userData)) {
- logd("Starting WebView with url: " + mUrl.toString());
- mWebView.loadUrl(mUrl.toString());
+ // Start the WebView
+ startWebView(mWebView, mUrl.toString(), mContentsType, mUserData);
+ }
+
+ /**
+ * Send the URL to the WebView as either a GET or POST request, based on the contents type:
+ * <ul>
+ * <li>
+ * CONTENTS_TYPE_UNSPECIFIED:
+ * If the user data exists, append it to the purchase URL and load it as a GET request.
+ * If the user data does not exist, load just the purchase URL as a GET request.
+ * </li>
+ * <li>
+ * CONTENTS_TYPE_JSON or CONTENTS_TYPE_XML:
+ * The user data must exist. Send the JSON or XML formatted user data in a POST request.
+ * If the user data is encoded, it must be prefaced by {@code encodedValue=} and will be
+ * encoded in Base64. Decode the user data and send it in the POST request.
+ * </li>
+ * </ul>
+ * @param webView The WebView to start.
+ * @param url The URL to start the WebView with.
+ * @param contentsType The contents type of the userData.
+ * @param userData The user data to send with the GET or POST request, if it exists.
+ */
+ @VisibleForTesting
+ public static void startWebView(@NonNull WebView webView, @NonNull String url, int contentsType,
+ @Nullable String userData) {
+ if (contentsType == CONTENTS_TYPE_UNSPECIFIED) {
+ logd("Starting WebView GET with url: " + url);
+ webView.loadUrl(url);
} else {
- logd("Starting WebView with url: " + mUrl.toString() + ", userData=" + userData);
- mWebView.postUrl(mUrl.toString(), userData.getBytes());
+ byte[] data = userData.getBytes();
+ String[] split = userData.split("encodedValue=");
+ if (split.length > 1) {
+ logd("Decoding encoded value: " + split[1]);
+ data = Base64.getDecoder().decode(split[1]);
+ }
+ logd("Starting WebView POST with url: " + url + ", contentsType: " + contentsType
+ + ", data: " + new String(data));
+ webView.postUrl(url, data);
}
}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
index 23b9766..9b33704 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiver.java
@@ -173,7 +173,9 @@
}
String purchaseUrl = intent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL);
- if (getPurchaseUrl(purchaseUrl) == null) {
+ String userData = intent.getStringExtra(SlicePurchaseController.EXTRA_USER_DATA);
+ String contentsType = intent.getStringExtra(SlicePurchaseController.EXTRA_CONTENTS_TYPE);
+ if (getPurchaseUrl(purchaseUrl, userData, TextUtils.isEmpty(contentsType)) == null) {
loge("isIntentValid: invalid purchase URL: " + purchaseUrl);
return false;
}
@@ -195,12 +197,39 @@
}
/**
+ * Get the {@link URL} from the given purchase URL String and user data, if it is valid.
+ *
+ * @param purchaseUrl The purchase URL String to use to create the URL.
+ * @param userData The user data parameter from the entitlement server.
+ * @param shouldAppendUserData If this is {@code true} and the {@code userData} exists,
+ * the {@code userData} should be appended to the {@code purchaseUrl} to create the URL.
+ * If this is false, only the {@code purchaseUrl} should be used and the {@code userData}
+ * will be sent as data to the POST request instead.
+ * @return The URL from the given purchase URL and user data or {@code null} if it is invalid.
+ */
+ @Nullable public static URL getPurchaseUrl(@Nullable String purchaseUrl,
+ @Nullable String userData, boolean shouldAppendUserData) {
+ if (purchaseUrl == null) {
+ return null;
+ }
+ // Only append user data if it exists, otherwise just return the purchase URL
+ if (!shouldAppendUserData || TextUtils.isEmpty(userData)) {
+ return getPurchaseUrl(purchaseUrl);
+ }
+ URL url = getPurchaseUrl(purchaseUrl + "?" + userData);
+ if (url == null) {
+ url = getPurchaseUrl(purchaseUrl);
+ }
+ return url;
+ }
+
+ /**
* Get the {@link URL} from the given purchase URL String, if it is valid.
*
* @param purchaseUrl The purchase URL String to use to create the URL.
* @return The purchase URL from the given String or {@code null} if it is invalid.
*/
- @Nullable public static URL getPurchaseUrl(@Nullable String purchaseUrl) {
+ @Nullable private static URL getPurchaseUrl(@Nullable String purchaseUrl) {
if (!URLUtil.isValidUrl(purchaseUrl)) {
return null;
}
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
index cc103fa..1ec180b 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseActivityTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.NotificationManager;
@@ -33,6 +34,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.test.ActivityUnitTestCase;
+import android.webkit.WebView;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -46,6 +48,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Base64;
+
@RunWith(AndroidJUnit4.class)
public class SlicePurchaseActivityTest extends ActivityUnitTestCase<SlicePurchaseActivity> {
private static final String CARRIER = "Some Carrier";
@@ -59,6 +63,7 @@
@Mock CarrierConfigManager mCarrierConfigManager;
@Mock NotificationManager mNotificationManager;
@Mock PersistableBundle mPersistableBundle;
+ @Mock WebView mWebView;
private SlicePurchaseActivity mSlicePurchaseActivity;
private Context mContext;
@@ -153,4 +158,23 @@
mSlicePurchaseActivity.onDismissFlow();
verify(mRequestFailedIntent).send();
}
+
+ @Test
+ public void testStartWebView() {
+ // unspecified contents type
+ SlicePurchaseActivity.startWebView(mWebView, URL, 0 /* CONTENTS_TYPE_UNSPECIFIED */, null);
+ verify(mWebView).loadUrl(eq(URL));
+
+ // specified contents type with user data
+ String userData = "userData";
+ byte[] userDataBytes = userData.getBytes();
+ SlicePurchaseActivity.startWebView(mWebView, URL, 1 /* CONTENTS_TYPE_JSON */, userData);
+ verify(mWebView).postUrl(eq(URL), eq(userDataBytes));
+
+ // specified contents type with encoded user data
+ byte[] encodedUserData = Base64.getEncoder().encode(userDataBytes);
+ userData = "encodedValue=" + new String(encodedUserData);
+ SlicePurchaseActivity.startWebView(mWebView, URL, 1 /* CONTENTS_TYPE_JSON */, userData);
+ verify(mWebView, times(2)).postUrl(eq(URL), eq(userDataBytes));
+ }
}
diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
index 952789c..61847b5 100644
--- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
+++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/SlicePurchaseBroadcastReceiverTest.java
@@ -160,14 +160,35 @@
"file:///android_asset/slice_store_test.html"
};
+ // test invalid URLs
for (String url : invalidUrls) {
- URL purchaseUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url);
+ URL purchaseUrl = SlicePurchaseBroadcastReceiver.getPurchaseUrl(url, null, false);
assertNull(purchaseUrl);
}
+ // test asset URL
assertEquals(SlicePurchaseController.SLICE_PURCHASE_TEST_FILE,
SlicePurchaseBroadcastReceiver.getPurchaseUrl(
- SlicePurchaseController.SLICE_PURCHASE_TEST_FILE).toString());
+ SlicePurchaseController.SLICE_PURCHASE_TEST_FILE, null, false).toString());
+
+ // test normal URL
+ String validUrl = "http://www.google.com";
+ assertEquals(validUrl,
+ SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, null, false).toString());
+
+ // test normal URL with user data but no append
+ String userData = "encryptedUserData=data";
+ assertEquals(validUrl,
+ SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, userData, false)
+ .toString());
+
+ // test normal URL with user data and append
+ assertEquals(validUrl + "?" + userData,
+ SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, userData, true).toString());
+
+ // test normal URL without user data and append
+ assertEquals(validUrl,
+ SlicePurchaseBroadcastReceiver.getPurchaseUrl(validUrl, null, true).toString());
}
@Test
diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml
index df58464..c6cacbc 100644
--- a/packages/InputDevices/res/values-bs/strings.xml
+++ b/packages/InputDevices/res/values-bs/strings.xml
@@ -34,7 +34,7 @@
<string name="keyboard_layout_brazilian" msgid="5117896443147781939">"brazilski"</string>
<string name="keyboard_layout_portuguese" msgid="2888198587329660305">"portugalski"</string>
<string name="keyboard_layout_slovak" msgid="2469379934672837296">"slovački"</string>
- <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenački"</string>
+ <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenski"</string>
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"turski"</string>
<string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"turski F"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinski"</string>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index 892fbc5..2562854 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -28,7 +28,7 @@
<string name="keyboard_layout_croatian" msgid="4172229471079281138">"क्रोएशियन"</string>
<string name="keyboard_layout_czech" msgid="1349256901452975343">"चेक"</string>
<string name="keyboard_layout_czech_qwerty" msgid="3331402534128515501">"चेक QWERTY स्टाइल"</string>
- <string name="keyboard_layout_estonian" msgid="8775830985185665274">"एस्टोनियाई"</string>
+ <string name="keyboard_layout_estonian" msgid="8775830985185665274">"एस्टोनियन"</string>
<string name="keyboard_layout_hungarian" msgid="4154963661406035109">"हंगेरियाई"</string>
<string name="keyboard_layout_icelandic" msgid="5836645650912489642">"आइसलैंडिक"</string>
<string name="keyboard_layout_brazilian" msgid="5117896443147781939">"ब्राज़ीलियाई"</string>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index a08a74b..3d0b945 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -12,13 +12,13 @@
<string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tyskt"</string>
<string name="keyboard_layout_french_label" msgid="813450119589383723">"Franskt"</string>
<string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franskt (Kanada)"</string>
- <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"Ryskt"</string>
+ <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"ryska"</string>
<string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"Ryskt, Mac"</string>
<string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"Spanskt"</string>
<string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"Franskt (Schweiz)"</string>
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tyskt (Schweiz)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiskt"</string>
- <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgariskt"</string>
+ <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bulgariska"</string>
<string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgariska (fonetiskt)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italienskt"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danskt"</string>
@@ -38,9 +38,9 @@
<string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkiskt"</string>
<string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"turkiska, F"</string>
<string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainskt"</string>
- <string name="keyboard_layout_arabic" msgid="5671970465174968712">"Arabiska"</string>
- <string name="keyboard_layout_greek" msgid="7289253560162386040">"Grekiska"</string>
- <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"Hebreiska"</string>
+ <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabiska"</string>
+ <string name="keyboard_layout_greek" msgid="7289253560162386040">"grekiska"</string>
+ <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebreiska"</string>
<string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauiska"</string>
<string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanska (latinamerikansk)"</string>
<string name="keyboard_layout_latvian" msgid="4405417142306250595">"lettiska"</string>
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
index ddbc907..bf3651b 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
@@ -17,7 +17,6 @@
package com.android.settingslib.utils;
import android.os.Build;
-import android.os.Build.VERSION;
import androidx.annotation.ChecksSdkIntAtLeast;
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 963bd9d..ed518f7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -23,7 +23,6 @@
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.MediaRoute2Info;
-import android.media.MediaRouter2Manager;
import android.media.RouteListingPreference;
import com.android.settingslib.R;
@@ -40,15 +39,21 @@
private CachedBluetoothDevice mCachedDevice;
private final AudioManager mAudioManager;
- BluetoothMediaDevice(Context context, CachedBluetoothDevice device,
- MediaRouter2Manager routerManager, MediaRoute2Info info, String packageName) {
- this(context, device, routerManager, info, packageName, null);
+ BluetoothMediaDevice(
+ Context context,
+ CachedBluetoothDevice device,
+ MediaRoute2Info info,
+ String packageName) {
+ this(context, device, info, packageName, null);
}
- BluetoothMediaDevice(Context context, CachedBluetoothDevice device,
- MediaRouter2Manager routerManager, MediaRoute2Info info, String packageName,
+ BluetoothMediaDevice(
+ Context context,
+ CachedBluetoothDevice device,
+ MediaRoute2Info info,
+ String packageName,
RouteListingPreference.Item item) {
- super(context, routerManager, info, packageName, item);
+ super(context, info, packageName, item);
mCachedDevice = device;
mAudioManager = context.getSystemService(AudioManager.class);
initDeviceRecord();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java
index c38dfe3..4e0ebd1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/ComplexMediaDevice.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
-import android.media.MediaRouter2Manager;
import android.media.RouteListingPreference;
import com.android.settingslib.R;
@@ -32,10 +31,12 @@
private final String mSummary = "";
- ComplexMediaDevice(Context context, MediaRouter2Manager routerManager,
- MediaRoute2Info info, String packageName,
+ ComplexMediaDevice(
+ Context context,
+ MediaRoute2Info info,
+ String packageName,
RouteListingPreference.Item item) {
- super(context, routerManager, info, packageName, item);
+ super(context, info, packageName, item);
}
// MediaRoute2Info.getName was made public on API 34, but exists since API 30.
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index b10d794..012cbc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -29,7 +29,6 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
-import android.media.MediaRouter2Manager;
import android.media.RouteListingPreference;
import androidx.annotation.VisibleForTesting;
@@ -43,15 +42,17 @@
private static final String TAG = "InfoMediaDevice";
- InfoMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
- String packageName, RouteListingPreference.Item item) {
- super(context, routerManager, info, packageName, item);
+ InfoMediaDevice(
+ Context context,
+ MediaRoute2Info info,
+ String packageName,
+ RouteListingPreference.Item item) {
+ super(context, info, packageName, item);
initDeviceRecord();
}
- InfoMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
- String packageName) {
- this(context, routerManager, info, packageName, null);
+ InfoMediaDevice(Context context, MediaRoute2Info info, String packageName) {
+ this(context, info, packageName, null);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3e864f9..7a48838 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -66,11 +66,14 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/** InfoMediaManager provide interface to get InfoMediaDevice list. */
@RequiresApi(Build.VERSION_CODES.R)
@@ -123,6 +126,8 @@
*/
protected abstract boolean connectDeviceWithoutPackageName(@NonNull MediaDevice device);
+ protected abstract void transferToRoute(@NonNull MediaRoute2Info route);
+
protected abstract void selectRoute(
@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info);
@@ -143,6 +148,8 @@
protected abstract void setSessionVolume(@NonNull RoutingSessionInfo info, int volume);
+ protected abstract void setRouteVolume(@NonNull MediaRoute2Info route, int volume);
+
@Nullable
protected abstract RouteListingPreference getRouteListingPreference();
@@ -165,23 +172,6 @@
@NonNull
protected abstract List<MediaRoute2Info> getTransferableRoutes(@NonNull String packageName);
- @NonNull
- protected abstract ComplexMediaDevice createComplexMediaDevice(
- MediaRoute2Info route, RouteListingPreference.Item routeListingPreferenceItem);
-
- @NonNull
- protected abstract InfoMediaDevice createInfoMediaDevice(
- MediaRoute2Info route, RouteListingPreference.Item routeListingPreferenceItem);
-
- @NonNull
- protected abstract PhoneMediaDevice createPhoneMediaDevice(MediaRoute2Info route,
- RouteListingPreference.Item routeListingPreferenceItem);
-
- @NonNull
- protected abstract BluetoothMediaDevice createBluetoothMediaDevice(
- MediaRoute2Info route, CachedBluetoothDevice cachedDevice,
- RouteListingPreference.Item routeListingPreferenceItem);
-
protected final void rebuildDeviceList() {
mMediaDevices.clear();
mCurrentConnectedDevice = null;
@@ -211,6 +201,20 @@
return mCurrentConnectedDevice;
}
+ /* package */ void connectToDevice(MediaDevice device) {
+ if (device.mRouteInfo == null) {
+ Log.w(TAG, "Unable to connect. RouteInfo is empty");
+ return;
+ }
+
+ if (TextUtils.isEmpty(mPackageName)) {
+ connectDeviceWithoutPackageName(device);
+ } else {
+ device.setConnectedRecord();
+ transferToRoute(device.mRouteInfo);
+ }
+ }
+
/**
* Add a MediaDevice to let it play current media.
*
@@ -335,7 +339,8 @@
final List<MediaDevice> deviceList = new ArrayList<>();
for (MediaRoute2Info route : getSelectableRoutes(info)) {
deviceList.add(
- createInfoMediaDevice(route, mPreferenceItemMap.get(route.getId())));
+ new InfoMediaDevice(
+ mContext, route, mPackageName, mPreferenceItemMap.get(route.getId())));
}
return deviceList;
}
@@ -361,7 +366,8 @@
final List<MediaDevice> deviceList = new ArrayList<>();
for (MediaRoute2Info route : getDeselectableRoutes(info)) {
deviceList.add(
- createInfoMediaDevice(route, mPreferenceItemMap.get(route.getId())));
+ new InfoMediaDevice(
+ mContext, route, mPackageName, mPreferenceItemMap.get(route.getId())));
Log.d(TAG, route.getName() + " is deselectable for " + mPackageName);
}
return deviceList;
@@ -388,11 +394,20 @@
final List<MediaDevice> deviceList = new ArrayList<>();
for (MediaRoute2Info route : getSelectedRoutes(info)) {
deviceList.add(
- createInfoMediaDevice(route, mPreferenceItemMap.get(route.getId())));
+ new InfoMediaDevice(
+ mContext, route, mPackageName, mPreferenceItemMap.get(route.getId())));
}
return deviceList;
}
+ /* package */ void adjustDeviceVolume(MediaDevice device, int volume) {
+ if (device.mRouteInfo == null) {
+ Log.w(TAG, "Unable to set volume. RouteInfo is empty");
+ return;
+ }
+ setRouteVolume(device.mRouteInfo, volume);
+ }
+
void adjustSessionVolume(RoutingSessionInfo info, int volume) {
if (info == null) {
Log.w(TAG, "Unable to adjust session volume. RoutingSessionInfo is empty");
@@ -585,7 +600,12 @@
case TYPE_REMOTE_CAR:
case TYPE_REMOTE_SMARTWATCH:
case TYPE_REMOTE_SMARTPHONE:
- mediaDevice = createInfoMediaDevice(route, mPreferenceItemMap.get(route.getId()));
+ mediaDevice =
+ new InfoMediaDevice(
+ mContext,
+ route,
+ mPackageName,
+ mPreferenceItemMap.get(route.getId()));
break;
case TYPE_BUILTIN_SPEAKER:
case TYPE_USB_DEVICE:
@@ -595,8 +615,12 @@
case TYPE_HDMI:
case TYPE_WIRED_HEADSET:
case TYPE_WIRED_HEADPHONES:
- mediaDevice = createPhoneMediaDevice(route,
- mPreferenceItemMap.getOrDefault(route.getId(), null));
+ mediaDevice =
+ new PhoneMediaDevice(
+ mContext,
+ route,
+ mPackageName,
+ mPreferenceItemMap.getOrDefault(route.getId(), null));
break;
case TYPE_HEARING_AID:
case TYPE_BLUETOOTH_A2DP:
@@ -606,14 +630,22 @@
final CachedBluetoothDevice cachedDevice =
mBluetoothManager.getCachedDeviceManager().findDevice(device);
if (cachedDevice != null) {
- mediaDevice = createBluetoothMediaDevice(route, cachedDevice,
- mPreferenceItemMap.getOrDefault(route.getId(), null));
+ mediaDevice =
+ new BluetoothMediaDevice(
+ mContext,
+ cachedDevice,
+ route,
+ mPackageName,
+ mPreferenceItemMap.getOrDefault(route.getId(), null));
}
break;
case TYPE_REMOTE_AUDIO_VIDEO_RECEIVER:
mediaDevice =
- createComplexMediaDevice(
- route, mPreferenceItemMap.get(route.getId()));
+ new ComplexMediaDevice(
+ mContext,
+ route,
+ mPackageName,
+ mPreferenceItemMap.get(route.getId()));
default:
Log.w(TAG, "addMediaDevice() unknown device type : " + deviceType);
break;
@@ -664,25 +696,62 @@
return filteredInfos;
}
+ /**
+ * Returns an ordered list of available devices based on the provided {@code
+ * routeListingPreferenceItems}.
+ *
+ * <p>The result has the following order:
+ *
+ * <ol>
+ * <li>Selected routes.
+ * <li>Not-selected system routes.
+ * <li>Not-selected, non-system, available routes sorted by route listing preference.
+ * </ol>
+ *
+ * @param selectedRoutes List of currently selected routes.
+ * @param availableRoutes List of available routes that match the app's requested route
+ * features.
+ * @param routeListingPreferenceItems Ordered list of {@link RouteListingPreference.Item} to
+ * sort routes with.
+ */
@DoNotInline
static List<MediaRoute2Info> arrangeRouteListByPreference(
- List<MediaRoute2Info> selectedRouteInfos, List<MediaRoute2Info> infolist,
- List<RouteListingPreference.Item> preferenceRouteListing) {
- final List<MediaRoute2Info> sortedInfoList = new ArrayList<>(selectedRouteInfos);
- infolist.removeAll(selectedRouteInfos);
- sortedInfoList.addAll(infolist.stream().filter(
- MediaRoute2Info::isSystemRoute).collect(Collectors.toList()));
- for (RouteListingPreference.Item item : preferenceRouteListing) {
- for (MediaRoute2Info info : infolist) {
- if (item.getRouteId().equals(info.getId())
- && !selectedRouteInfos.contains(info)
- && !info.isSystemRoute()) {
- sortedInfoList.add(info);
- break;
- }
+ List<MediaRoute2Info> selectedRoutes,
+ List<MediaRoute2Info> availableRoutes,
+ List<RouteListingPreference.Item> routeListingPreferenceItems) {
+ Set<String> sortedRouteIds = new LinkedHashSet<>();
+
+ // Add selected routes first.
+ for (MediaRoute2Info selectedRoute : selectedRoutes) {
+ sortedRouteIds.add(selectedRoute.getId());
+ }
+
+ // Add not-yet-added system routes.
+ for (MediaRoute2Info availableRoute : availableRoutes) {
+ if (availableRoute.isSystemRoute()) {
+ sortedRouteIds.add(availableRoute.getId());
}
}
- return sortedInfoList;
+
+ // Create a mapping from id to route to avoid a quadratic search.
+ Map<String, MediaRoute2Info> idToRouteMap =
+ Stream.concat(selectedRoutes.stream(), availableRoutes.stream())
+ .collect(
+ Collectors.toMap(
+ MediaRoute2Info::getId,
+ Function.identity(),
+ (route1, route2) -> route1));
+
+ // Add not-selected routes that match RLP items. All system routes have already been
+ // added at this point.
+ for (RouteListingPreference.Item item : routeListingPreferenceItems) {
+ MediaRoute2Info route = idToRouteMap.get(item.getRouteId());
+ if (route != null) {
+ sortedRouteIds.add(route.getId());
+ }
+ }
+
+ return sortedRouteIds.stream().map(idToRouteMap::get).collect(Collectors.toList());
}
@DoNotInline
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 987f616..8479df1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -188,11 +188,7 @@
}
device.setState(MediaDeviceState.STATE_CONNECTING);
- if (TextUtils.isEmpty(mPackageName)) {
- mInfoMediaManager.connectDeviceWithoutPackageName(device);
- } else {
- device.connect();
- }
+ mInfoMediaManager.connectToDevice(device);
return true;
}
@@ -376,6 +372,16 @@
}
/**
+ * Requests a volume change for a specific media device.
+ *
+ * This operation is different from {@link #adjustSessionVolume(String, int)}, which changes the
+ * volume of the overall session.
+ */
+ public void adjustDeviceVolume(MediaDevice device, int volume) {
+ mInfoMediaManager.adjustDeviceVolume(device, volume);
+ }
+
+ /**
* Adjust the volume of session.
*
* @param sessionId the value of media session id
@@ -559,9 +565,7 @@
final CachedBluetoothDevice cachedDevice =
cachedDeviceManager.findDevice(device);
if (isBondedMediaDevice(cachedDevice) && isMutingExpectedDevice(cachedDevice)) {
- return new BluetoothMediaDevice(mContext,
- cachedDevice,
- null, null, mPackageName);
+ return new BluetoothMediaDevice(mContext, cachedDevice, null, mPackageName);
}
}
return null;
@@ -607,9 +611,8 @@
unRegisterDeviceAttributeChangeCallback();
mDisconnectedMediaDevices.clear();
for (CachedBluetoothDevice cachedDevice : cachedBluetoothDeviceList) {
- final MediaDevice mediaDevice = new BluetoothMediaDevice(mContext,
- cachedDevice,
- null, null, mPackageName);
+ final MediaDevice mediaDevice =
+ new BluetoothMediaDevice(mContext, cachedDevice, null, mPackageName);
if (!mMediaDevices.contains(mediaDevice)) {
cachedDevice.registerCallback(mDeviceAttributeChangeCallback);
mDisconnectedMediaDevices.add(mediaDevice);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
index c86a943..b7ac1dce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/ManagerInfoMediaManager.java
@@ -28,7 +28,6 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.util.ArrayList;
@@ -81,6 +80,11 @@
}
@Override
+ protected void transferToRoute(@NonNull MediaRoute2Info route) {
+ mRouterManager.transfer(mPackageName, route);
+ }
+
+ @Override
protected boolean connectDeviceWithoutPackageName(@NonNull MediaDevice device) {
final RoutingSessionInfo info = mRouterManager.getSystemRoutingSession(null);
if (info != null) {
@@ -129,6 +133,11 @@
}
@Override
+ protected void setRouteVolume(@NonNull MediaRoute2Info route, int volume) {
+ mRouterManager.setRouteVolume(route, volume);
+ }
+
+ @Override
@Nullable
protected RouteListingPreference getRouteListingPreference() {
return mRouterManager.getRouteListingPreference(mPackageName);
@@ -167,40 +176,6 @@
return mRouterManager.getTransferableRoutes(packageName);
}
- @Override
- @NonNull
- protected ComplexMediaDevice createComplexMediaDevice(
- MediaRoute2Info route, RouteListingPreference.Item routeListingPreferenceItem) {
- return new ComplexMediaDevice(
- mContext, mRouterManager, route, mPackageName, routeListingPreferenceItem);
- }
-
- @Override
- @NonNull
- protected InfoMediaDevice createInfoMediaDevice(
- MediaRoute2Info route, RouteListingPreference.Item routeListingPreferenceItem) {
- return new InfoMediaDevice(
- mContext, mRouterManager, route, mPackageName, routeListingPreferenceItem);
- }
-
- @Override
- @NonNull
- protected PhoneMediaDevice createPhoneMediaDevice(MediaRoute2Info route,
- RouteListingPreference.Item routeListingPreferenceItem) {
- return new PhoneMediaDevice(mContext, mRouterManager, route, mPackageName,
- routeListingPreferenceItem);
- }
-
- @Override
- @NonNull
- protected BluetoothMediaDevice createBluetoothMediaDevice(
- MediaRoute2Info route, CachedBluetoothDevice cachedDevice,
- RouteListingPreference.Item routeListingPreferenceItem) {
- return new BluetoothMediaDevice(
- mContext, cachedDevice, mRouterManager, route, mPackageName,
- routeListingPreferenceItem);
- }
-
@VisibleForTesting
/* package */ final class RouterManagerCallback implements MediaRouter2Manager.Callback {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index a9d15f3..9234d37 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -50,7 +50,6 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
-import android.media.MediaRouter2Manager;
import android.media.NearbyDevice;
import android.media.RouteListingPreference;
import android.os.Build;
@@ -116,15 +115,16 @@
protected final Context mContext;
protected final MediaRoute2Info mRouteInfo;
- protected final MediaRouter2Manager mRouterManager;
protected final RouteListingPreference.Item mItem;
protected final String mPackageName;
- MediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
- String packageName, RouteListingPreference.Item item) {
+ MediaDevice(
+ Context context,
+ MediaRoute2Info info,
+ String packageName,
+ RouteListingPreference.Item item) {
mContext = context;
mRouteInfo = info;
- mRouterManager = routerManager;
mPackageName = packageName;
mItem = item;
setType(info);
@@ -306,20 +306,6 @@
public abstract boolean isConnected();
/**
- * Request to set volume.
- *
- * @param volume is the new value.
- */
-
- public void requestSetVolume(int volume) {
- if (mRouteInfo == null) {
- Log.w(TAG, "Unable to set volume. RouteInfo is empty");
- return;
- }
- mRouterManager.setRouteVolume(mRouteInfo, volume);
- }
-
- /**
* Get max volume from MediaDevice.
*
* @return max volume.
@@ -393,21 +379,6 @@
}
/**
- * Transfer MediaDevice for media
- *
- * @return result of transfer media
- */
- public boolean connect() {
- if (mRouteInfo == null) {
- Log.w(TAG, "Unable to connect. RouteInfo is empty");
- return false;
- }
- setConnectedRecord();
- mRouterManager.transfer(mPackageName, mRouteInfo);
- return true;
- }
-
- /**
* Stop transfer MediaDevice
*/
public void disconnect() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index accd88c..41afc7b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -29,7 +29,6 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
-import android.media.MediaRouter2Manager;
import android.media.RouteListingPreference;
import androidx.annotation.VisibleForTesting;
@@ -52,14 +51,16 @@
private final DeviceIconUtil mDeviceIconUtil;
- PhoneMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
- String packageName) {
- this(context, routerManager, info, packageName, null);
+ PhoneMediaDevice(Context context, MediaRoute2Info info, String packageName) {
+ this(context, info, packageName, null);
}
- PhoneMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
- String packageName, RouteListingPreference.Item item) {
- super(context, routerManager, info, packageName, item);
+ PhoneMediaDevice(
+ Context context,
+ MediaRoute2Info info,
+ String packageName,
+ RouteListingPreference.Item item) {
+ super(context, info, packageName, item);
mDeviceIconUtil = new DeviceIconUtil();
initDeviceRecord();
}
diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp
index c037c40..5c55a43 100644
--- a/packages/SettingsLib/tests/robotests/Android.bp
+++ b/packages/SettingsLib/tests/robotests/Android.bp
@@ -42,10 +42,7 @@
name: "SettingsLibRoboTests",
srcs: ["src/**/*.java"],
static_libs: [
- "Settings_robolectric_meta_service_file",
- "Robolectric_shadows_androidx_fragment_upstream",
"SettingsLib-robo-testutils",
- "androidx.fragment_fragment",
"androidx.test.core",
"androidx.core_core",
"testng", // TODO: remove once JUnit on Android provides assertThrows
@@ -56,20 +53,6 @@
test_options: {
timeout: 36000,
},
- upstream: true,
-}
-
-java_genrule {
- name: "Settings_robolectric_meta_service_file",
- out: ["robolectric_meta_service_file.jar"],
- tools: ["soong_zip"],
- cmd: "mkdir -p $(genDir)/META-INF/services/ && touch $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider &&" +
- "echo -e 'org.robolectric.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
- "echo -e 'org.robolectric.shadows.multidex.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
- "echo -e 'org.robolectric.shadows.httpclient.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
- //"echo -e 'com.android.settings.testutils.shadow.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
- "echo -e 'com.android.settingslib.testutils.shadow.Shadows' >> $(genDir)/META-INF/services/org.robolectric.internal.ShadowProvider && " +
- "$(location soong_zip) -o $(out) -C $(genDir) -D $(genDir)/META-INF/services/",
}
java_library {
@@ -77,23 +60,9 @@
srcs: [
"testutils/com/android/settingslib/testutils/**/*.java",
],
- javacflags: [
- "-Aorg.robolectric.annotation.processing.shadowPackage=com.android.settingslib.testutils.shadow",
- "-Aorg.robolectric.annotation.processing.sdkCheckMode=ERROR",
- // Uncomment the below to debug annotation processors not firing.
- //"-verbose",
- //"-XprintRounds",
- //"-XprintProcessorInfo",
- //"-Xlint",
- //"-J-verbose",
- ],
- plugins: [
- "auto_value_plugin_1.9",
- "auto_value_builder_plugin_1.9",
- "Robolectric_processor_upstream",
- ],
+
libs: [
- "Robolectric_all-target_upstream",
+ "Robolectric_all-target",
"mockito-robolectric-prebuilt",
"truth-prebuilt",
],
diff --git a/packages/SettingsLib/tests/robotests/config/robolectric.properties b/packages/SettingsLib/tests/robotests/config/robolectric.properties
index 2a9e50d..fab7251 100644
--- a/packages/SettingsLib/tests/robotests/config/robolectric.properties
+++ b/packages/SettingsLib/tests/robotests/config/robolectric.properties
@@ -1,2 +1 @@
sdk=NEWEST_SDK
-instrumentedPackages=androidx.preference
diff --git a/packages/SettingsLib/tests/robotests/fragment/Android.bp b/packages/SettingsLib/tests/robotests/fragment/Android.bp
deleted file mode 100644
index 3e67156..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-//#############################################
-// Compile Robolectric shadows framework misapplied to androidx
-//#############################################
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_library {
- name: "Robolectric_shadows_androidx_fragment_upstream",
- srcs: [
- "src/main/java/**/*.java",
- "src/main/java/**/*.kt",
- ],
- javacflags: [
- "-Aorg.robolectric.annotation.processing.shadowPackage=org.robolectric.shadows.androidx.fragment",
- "-Aorg.robolectric.annotation.processing.sdkCheckMode=ERROR",
- // Uncomment the below to debug annotation processors not firing.
- //"-verbose",
- //"-XprintRounds",
- //"-XprintProcessorInfo",
- //"-Xlint",
- //"-J-verbose",
- ],
- libs: [
- "Robolectric_all-target_upstream",
- "androidx.fragment_fragment",
- ],
- plugins: [
- "auto_value_plugin_1.9",
- "auto_value_builder_plugin_1.9",
- "Robolectric_processor_upstream",
- ],
-
-}
diff --git a/packages/SettingsLib/tests/robotests/fragment/BUILD b/packages/SettingsLib/tests/robotests/fragment/BUILD
deleted file mode 100644
index 393a02e..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/BUILD
+++ /dev/null
@@ -1,69 +0,0 @@
-load("//third_party/java/android/android_sdk_linux/extras/android/compatibility/jetify:jetify.bzl", "jetify_android_library", "jetify_android_local_test")
-
-package(
- default_applicable_licenses = ["//third_party/java_src/robolectric:license"],
- default_visibility = ["//third_party/java_src/robolectric:__subpackages__"],
-)
-
-licenses(["notice"])
-
-#==============================================================================
-# Test resources library
-#==============================================================================
-jetify_android_library(
- name = "test_resources",
- custom_package = "org.robolectric.shadows.androidx.fragment",
- manifest = "src/test/AndroidManifest.xml",
- resource_files = glob(
- ["src/test/resources/**/*"],
- ),
-)
-
-#==============================================================================
-# AndroidX fragment module library
-#==============================================================================
-jetify_android_library(
- name = "androidx_fragment",
- testonly = 1,
- srcs = glob(
- ["src/main/java/**"],
- ),
- custom_package = "org.robolectric.shadows.androidx.fragment",
- javacopts = [
- "-Aorg.robolectric.annotation.processing.shadowPackage=org.robolectric.shadows.androidx.fragment",
- ],
- jetify_sources = True,
- plugins = [
- "//java/com/google/thirdparty/robolectric/processor",
- ],
- deps = [
- "//third_party/java/androidx/core",
- "//third_party/java/androidx/fragment",
- "//third_party/java/androidx/lifecycle",
- "//third_party/java_src/robolectric/shadowapi",
- "//third_party/java_src/robolectric/shadows/framework",
- ],
-)
-
-[
- jetify_android_local_test(
- name = "test_" + src.rstrip(".java"),
- size = "small",
- srcs = glob(
- ["src/test/java/**/*.java"],
- ),
- jetify_sources = True,
- deps = [
- ":androidx_fragment",
- ":test_resources",
- "//third_party/java/androidx/fragment",
- "//third_party/java/androidx/loader",
- "//third_party/java/mockito",
- "//third_party/java/robolectric",
- "//third_party/java/truth",
- ],
- )
- for src in glob(
- ["src/test/java/**/*Test.java"],
- )
-]
diff --git a/packages/SettingsLib/tests/robotests/fragment/build.gradle b/packages/SettingsLib/tests/robotests/fragment/build.gradle
deleted file mode 100644
index d9dcd84..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/build.gradle
+++ /dev/null
@@ -1,48 +0,0 @@
-plugins {
- id "net.ltgt.errorprone" version "0.0.13"
-}
-
-apply plugin: 'com.android.library'
-
-android {
- compileSdkVersion 28
-
- android {
- sourceSets {
- main {
- res.srcDirs = ['src/test/resources/res']
- }
- }
- testOptions {
- unitTests {
- includeAndroidResources = true
- }
- }
- }
-}
-
-dependencies {
- // Project dependencies
- compileOnly project(":robolectric")
-
- // Compile dependencies
- compileOnly AndroidSdk.MAX_SDK.coordinates
- compileOnly "androidx.core:core:1.0.0-rc02"
- compileOnly 'androidx.fragment:fragment:1.0.0-rc02'
- compileOnly "androidx.lifecycle:lifecycle-viewmodel:2.0.0-rc01"
- compileOnly "androidx.lifecycle:lifecycle-common:2.0.0-beta01"
-
- // Testing dependencies
- testImplementation "com.google.truth:truth:0.44"
- testImplementation "org.mockito:mockito-core:2.5.4"
- testImplementation "androidx.arch.core:core-common:2.0.0-beta01"
- testImplementation "androidx.arch.core:core-runtime:2.0.0-rc01"
- testImplementation "androidx.collection:collection:1.0.0-rc01"
- testImplementation "androidx.core:core:1.0.0-rc02"
- testImplementation 'androidx.fragment:fragment:1.0.0-rc02'
- testImplementation "androidx.lifecycle:lifecycle-viewmodel:2.0.0-rc01"
- testImplementation "androidx.lifecycle:lifecycle-common:2.0.0-beta01"
- testImplementation "androidx.lifecycle:lifecycle-runtime:2.0.0-rc01"
- testImplementation "androidx.lifecycle:lifecycle-livedata-core:2.0.0-rc01"
- testImplementation "androidx.loader:loader:1.0.0-rc02"
-}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java
deleted file mode 100644
index c688683..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/FragmentController.java
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.robolectric.shadows.androidx.fragment;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.widget.LinearLayout;
-
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-
-import org.robolectric.android.controller.ActivityController;
-import org.robolectric.android.controller.ComponentController;
-import org.robolectric.util.ReflectionHelpers;
-
-/** A Controller that can be used to drive the lifecycle of a {@link Fragment} */
-public class FragmentController<F extends Fragment>
- extends ComponentController<FragmentController<F>, F> {
-
- private final F mFragment;
- private final ActivityController<? extends FragmentActivity> mActivityController;
-
- private FragmentController(F fragment, Class<? extends FragmentActivity> activityClass) {
- this(fragment, activityClass, null /*intent*/, null /*arguments*/);
- }
-
- private FragmentController(
- F fragment, Class<? extends FragmentActivity> activityClass, Intent intent) {
- this(fragment, activityClass, intent, null /*arguments*/);
- }
-
- private FragmentController(
- F fragment, Class<? extends FragmentActivity> activityClass, Bundle arguments) {
- this(fragment, activityClass, null /*intent*/, arguments);
- }
-
- private FragmentController(
- F fragment,
- Class<? extends FragmentActivity> activityClass,
- Intent intent,
- Bundle arguments) {
- super(fragment, intent);
- this.mFragment = fragment;
- if (arguments != null) {
- this.mFragment.setArguments(arguments);
- }
- this.mActivityController =
- ActivityController.of(ReflectionHelpers.callConstructor(activityClass), intent);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(F fragment) {
- return new FragmentController<>(fragment, FragmentControllerActivity.class);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment and intent.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @param intent the intent which will be retained by activity
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(F fragment, Intent intent) {
- return new FragmentController<>(fragment, FragmentControllerActivity.class, intent);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment and arguments.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @param arguments the arguments which will be retained by fragment
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(F fragment, Bundle arguments) {
- return new FragmentController<>(fragment, FragmentControllerActivity.class, arguments);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment and activity class.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @param activityClass the activity which will be attached by fragment
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(
- F fragment, Class<? extends FragmentActivity> activityClass) {
- return new FragmentController<>(fragment, activityClass);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment, intent and arguments.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @param intent the intent which will be retained by activity
- * @param arguments the arguments which will be retained by fragment
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(
- F fragment, Intent intent, Bundle arguments) {
- return new FragmentController<>(fragment, FragmentControllerActivity.class, intent,
- arguments);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment, activity class and intent.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @param activityClass the activity which will be attached by fragment
- * @param intent the intent which will be retained by activity
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(
- F fragment, Class<? extends FragmentActivity> activityClass, Intent intent) {
- return new FragmentController<>(fragment, activityClass, intent);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment, activity class and arguments.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @param activityClass the activity which will be attached by fragment
- * @param arguments the arguments which will be retained by fragment
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(
- F fragment, Class<? extends FragmentActivity> activityClass, Bundle arguments) {
- return new FragmentController<>(fragment, activityClass, arguments);
- }
-
- /**
- * Generate the {@link FragmentController} for specific fragment, activity class, intent and
- * arguments.
- *
- * @param fragment the fragment which you'd like to drive lifecycle
- * @param activityClass the activity which will be attached by fragment
- * @param intent the intent which will be retained by activity
- * @param arguments the arguments which will be retained by fragment
- * @return {@link FragmentController}
- */
- public static <F extends Fragment> FragmentController<F> of(
- F fragment,
- Class<? extends FragmentActivity> activityClass,
- Intent intent,
- Bundle arguments) {
- return new FragmentController<>(fragment, activityClass, intent, arguments);
- }
-
- /**
- * Sets up the given fragment by attaching it to an activity, calling its onCreate() through
- * onResume() lifecycle methods, and then making it visible. Note that the fragment will be
- * added
- * to the view with ID 1.
- */
- public static <F extends Fragment> F setupFragment(F fragment) {
- return FragmentController.of(fragment).create().start().resume().visible().get();
- }
-
- /**
- * Sets up the given fragment by attaching it to an activity, calling its onCreate() through
- * onResume() lifecycle methods, and then making it visible. Note that the fragment will be
- * added
- * to the view with ID 1.
- */
- public static <F extends Fragment> F setupFragment(
- F fragment, Class<? extends FragmentActivity> fragmentActivityClass) {
- return FragmentController.of(fragment, fragmentActivityClass)
- .create()
- .start()
- .resume()
- .visible()
- .get();
- }
-
- /**
- * Sets up the given fragment by attaching it to an activity created with the given bundle,
- * calling its onCreate() through onResume() lifecycle methods, and then making it visible. Note
- * that the fragment will be added to the view with ID 1.
- */
- public static <F extends Fragment> F setupFragment(
- F fragment, Class<? extends FragmentActivity> fragmentActivityClass, Bundle bundle) {
- return FragmentController.of(fragment, fragmentActivityClass)
- .create(bundle)
- .start()
- .resume()
- .visible()
- .get();
- }
-
- /**
- * Sets up the given fragment by attaching it to an activity created with the given bundle and
- * container id, calling its onCreate() through onResume() lifecycle methods, and then making it
- * visible.
- */
- public static <F extends Fragment> F setupFragment(
- F fragment,
- Class<? extends FragmentActivity> fragmentActivityClass,
- int containerViewId,
- Bundle bundle) {
- return FragmentController.of(fragment, fragmentActivityClass)
- .create(containerViewId, bundle)
- .start()
- .resume()
- .visible()
- .get();
- }
-
- /**
- * Creates the activity with {@link Bundle} and adds the fragment to the view with ID {@code
- * contentViewId}.
- */
- public FragmentController<F> create(final int contentViewId, final Bundle bundle) {
- shadowMainLooper.runPaused(
- new Runnable() {
- @Override
- public void run() {
- mActivityController
- .create(bundle)
- .get()
- .getSupportFragmentManager()
- .beginTransaction()
- .add(contentViewId, mFragment)
- .commit();
- }
- });
- return this;
- }
-
- /**
- * Creates the activity with {@link Bundle} and adds the fragment to it. Note that the fragment
- * will be added to the view with ID 1.
- */
- public FragmentController<F> create(final Bundle bundle) {
- return create(1, bundle);
- }
-
- /**
- * Creates the {@link Fragment} in a newly initialized state and hence will receive a null
- * savedInstanceState {@link Bundle parameter}
- */
- @Override
- public FragmentController<F> create() {
- return create(null);
- }
-
- /** Drive lifecycle of activity to Start lifetime */
- public FragmentController<F> start() {
- shadowMainLooper.runPaused(
- new Runnable() {
- @Override
- public void run() {
- mActivityController.start();
- }
- });
- return this;
- }
-
- /** Drive lifecycle of activity to Resume lifetime */
- public FragmentController<F> resume() {
- shadowMainLooper.runPaused(
- new Runnable() {
- @Override
- public void run() {
- mActivityController.resume();
- }
- });
- return this;
- }
-
- /** Drive lifecycle of activity to Pause lifetime */
- public FragmentController<F> pause() {
- shadowMainLooper.runPaused(
- new Runnable() {
- @Override
- public void run() {
- mActivityController.pause();
- }
- });
- return this;
- }
-
- /** Drive lifecycle of activity to Stop lifetime */
- public FragmentController<F> stop() {
- shadowMainLooper.runPaused(
- new Runnable() {
- @Override
- public void run() {
- mActivityController.stop();
- }
- });
- return this;
- }
-
- /** Drive lifecycle of activity to Destroy lifetime */
- @Override
- public FragmentController<F> destroy() {
- shadowMainLooper.runPaused(
- new Runnable() {
- @Override
- public void run() {
- mActivityController.destroy();
- }
- });
- return this;
- }
-
- /** Let activity can be visible lifetime */
- public FragmentController<F> visible() {
- shadowMainLooper.runPaused(
- new Runnable() {
- @Override
- public void run() {
- mActivityController.visible();
- }
- });
- return this;
- }
-
- private static class FragmentControllerActivity extends FragmentActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- LinearLayout view = new LinearLayout(this);
- view.setId(1);
-
- setContentView(view);
- }
- }
-}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
deleted file mode 100644
index dd89441..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Testing infrastructure for androidx.fragment library.
- *
- * <p>To use this in your project, add the artifact {@code
- * org.robolectric:shadows-androidx-fragment} to your project.
- */
-package org.robolectric.shadows.androidx.fragment;
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml
deleted file mode 100644
index 8493c02..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/src/test/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.robolectric.shadows.androidx.fragment">
-
- <uses-sdk android:targetSdkVersion="28"/>
-</manifest>
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java b/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java
deleted file mode 100644
index ef63058..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/src/test/java/org/robolectric/shadows/androidx/fragment/FragmentControllerTest.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.robolectric.shadows.androidx.fragment;
-
-import static android.os.Looper.getMainLooper;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.robolectric.Shadows.shadowOf;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Tests for {@link FragmentController} */
-@RunWith(RobolectricTestRunner.class)
-public class FragmentControllerTest {
-
- @After
- public void tearDown() {
- TranscriptFragment.clearLifecycleEvents();
- }
-
- @Test
- public void initialNotAttached() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment());
-
- assertThat(controller.get().getView()).isNull();
- assertThat(controller.get().getActivity()).isNull();
- assertThat(controller.get().isAdded()).isFalse();
- }
-
- @Test
- public void initialNotAttached_customActivity() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class);
-
- assertThat(controller.get().getView()).isNull();
- assertThat(controller.get().getActivity()).isNull();
- assertThat(controller.get().isAdded()).isFalse();
- }
-
- @Test
- public void attachedAfterCreate() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment());
-
- controller.create();
- shadowOf(getMainLooper()).idle();
-
- assertThat(controller.get().getActivity()).isNotNull();
- assertThat(controller.get().isAdded()).isTrue();
- assertThat(controller.get().isResumed()).isFalse();
- }
-
- @Test
- public void attachedAfterCreate_customActivity() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class);
-
- controller.create();
- shadowOf(getMainLooper()).idle();
-
- assertThat(controller.get().getActivity()).isNotNull();
- assertThat(controller.get().getActivity()).isInstanceOf(TestActivity.class);
- assertThat(controller.get().isAdded()).isTrue();
- assertThat(controller.get().isResumed()).isFalse();
- }
-
- @Test
- public void attachedAfterCreate_customizedViewId() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), CustomizedViewIdTestActivity.class);
-
- controller.create(R.id.custom_activity_view, null).start();
-
- assertThat(controller.get().getView()).isNotNull();
- assertThat(controller.get().getActivity()).isNotNull();
- assertThat(controller.get().isAdded()).isTrue();
- assertThat(controller.get().isResumed()).isFalse();
- assertThat((TextView) controller.get().getView().findViewById(R.id.tacos)).isNotNull();
- }
-
- @Test
- public void hasViewAfterStart() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment());
-
- controller.create().start();
-
- assertThat(controller.get().getView()).isNotNull();
- }
-
- @Test
- public void isResumed() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class);
-
- controller.create().start().resume();
-
- assertThat(controller.get().getView()).isNotNull();
- assertThat(controller.get().getActivity()).isNotNull();
- assertThat(controller.get().isAdded()).isTrue();
- assertThat(controller.get().isResumed()).isTrue();
- assertThat((TextView) controller.get().getView().findViewById(R.id.tacos)).isNotNull();
- }
-
- @Test
- public void isPaused() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class);
-
- controller.create().start().resume().pause();
-
- assertThat(controller.get().getView()).isNotNull();
- assertThat(controller.get().getActivity()).isNotNull();
- assertThat(controller.get().isAdded()).isTrue();
- assertThat(controller.get().isResumed()).isFalse();
- assertThat(controller.get().getLifecycleEvents())
- .containsExactly("onCreate", "onStart", "onResume", "onPause")
- .inOrder();
- }
-
- @Test
- public void isStopped() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class);
-
- controller.create().start().resume().pause().stop();
-
- assertThat(controller.get().getView()).isNotNull();
- assertThat(controller.get().getActivity()).isNotNull();
- assertThat(controller.get().isAdded()).isTrue();
- assertThat(controller.get().isResumed()).isFalse();
- assertThat(controller.get().getLifecycleEvents())
- .containsExactly("onCreate", "onStart", "onResume", "onPause", "onStop")
- .inOrder();
- }
-
- @Test
- public void withIntent() {
- final Intent intent = generateTestIntent();
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class, intent);
-
- controller.create();
- shadowOf(getMainLooper()).idle();
- final Intent intentInFragment = controller.get().getActivity().getIntent();
-
- assertThat(intentInFragment.getAction()).isEqualTo("test_action");
- assertThat(intentInFragment.getExtras().getString("test_key")).isEqualTo("test_value");
- }
-
- @Test
- public void withArguments() {
- final Bundle bundle = generateTestBundle();
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class, bundle);
-
- controller.create();
- final Bundle args = controller.get().getArguments();
-
- assertThat(args.getString("test_key")).isEqualTo("test_value");
- }
-
- @Test
- public void withIntentAndArguments() {
- final Bundle bundle = generateTestBundle();
- final Intent intent = generateTestIntent();
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class, intent, bundle);
-
- controller.create();
- shadowOf(getMainLooper()).idle();
- final Intent intentInFragment = controller.get().getActivity().getIntent();
- final Bundle args = controller.get().getArguments();
-
- assertThat(intentInFragment.getAction()).isEqualTo("test_action");
- assertThat(intentInFragment.getExtras().getString("test_key")).isEqualTo("test_value");
- assertThat(args.getString("test_key")).isEqualTo("test_value");
- }
-
- @Test
- public void visible() {
- final FragmentController<TranscriptFragment> controller =
- FragmentController.of(new TranscriptFragment(), TestActivity.class);
-
- controller.create().start().resume();
-
- assertThat(controller.get().isVisible()).isFalse();
-
- controller.visible();
-
- assertThat(controller.get().isVisible()).isTrue();
- }
-
- @Test
- public void setupFragmentWithFragment_fragmentHasCorrectLifecycle() {
- TranscriptFragment fragment = FragmentController.setupFragment(new TranscriptFragment());
-
- assertThat(fragment.getLifecycleEvents())
- .containsExactly("onCreate", "onStart", "onResume")
- .inOrder();
- assertThat(fragment.isVisible()).isTrue();
- }
-
- @Test
- public void setupFragmentWithFragmentAndActivity_fragmentHasCorrectLifecycle() {
- TranscriptFragment fragment =
- FragmentController.setupFragment(new TranscriptFragment(), TestActivity.class);
-
- assertThat(fragment.getLifecycleEvents())
- .containsExactly("onCreate", "onStart", "onResume")
- .inOrder();
- assertThat(fragment.isVisible()).isTrue();
- }
-
- @Test
- public void setupFragmentWithFragmentAndActivityAndBundle_HasCorrectLifecycle() {
- Bundle testBundle = generateTestBundle();
- TranscriptFragment fragment =
- FragmentController.setupFragment(new TranscriptFragment(), TestActivity.class,
- testBundle);
-
- assertThat(fragment.getLifecycleEvents())
- .containsExactly("onCreate", "onStart", "onResume")
- .inOrder();
- assertThat(fragment.isVisible()).isTrue();
- }
-
- @Test
- public void
- setupFragmentWithFragment_Activity_ContainViewIdAndBundle_HasCorrectLifecycle() {
- Bundle testBundle = generateTestBundle();
- TranscriptFragment fragment =
- FragmentController.setupFragment(
- new TranscriptFragment(),
- CustomizedViewIdTestActivity.class,
- R.id.custom_activity_view,
- testBundle);
-
- assertThat(fragment.getLifecycleEvents())
- .containsExactly("onCreate", "onStart", "onResume")
- .inOrder();
- assertThat(fragment.isVisible()).isTrue();
- }
-
- private Intent generateTestIntent() {
- final Intent testIntent = new Intent("test_action").putExtra("test_key", "test_value");
- return testIntent;
- }
-
- private Bundle generateTestBundle() {
- final Bundle testBundle = new Bundle();
- testBundle.putString("test_key", "test_value");
-
- return testBundle;
- }
-
- /** A Fragment which can record lifecycle status for test. */
- public static class TranscriptFragment extends Fragment {
-
- public static final List<String> sLifecycleEvents = new ArrayList<>();
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- sLifecycleEvents.add("onCreate");
- }
-
- @Override
- public void onStart() {
- super.onStart();
- sLifecycleEvents.add("onStart");
- }
-
- @Override
- public void onResume() {
- super.onResume();
- sLifecycleEvents.add("onResume");
- }
-
- @Override
- public void onPause() {
- super.onPause();
- sLifecycleEvents.add("onPause");
- }
-
- @Override
- public void onStop() {
- super.onStop();
- sLifecycleEvents.add("onStop");
- }
-
- @Override
- public View onCreateView(
- LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment_contents, container, false);
- }
-
- public List<String> getLifecycleEvents() {
- return sLifecycleEvents;
- }
-
- public static void clearLifecycleEvents() {
- sLifecycleEvents.clear();
- }
- }
-
- /** A Activity which set a default view for test. */
- public static class TestActivity extends FragmentActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- LinearLayout view = new LinearLayout(this);
- view.setId(1);
-
- setContentView(view);
- }
- }
-
- /** A Activity which has a custom view for test. */
- public static class CustomizedViewIdTestActivity extends FragmentActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.custom_activity_view);
- }
- }
-}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml
deleted file mode 100644
index c074f30..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/custom_activity_view.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/custom_activity_view"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
-
-</LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml b/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml
deleted file mode 100644
index 425b2bb..0000000
--- a/packages/SettingsLib/tests/robotests/fragment/src/test/resources/res/layout/fragment_contents.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/tacos"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="TACOS"/>
-
- <TextView
- android:id="@+id/burritos"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="BURRITOS"/>
-
-</LinearLayout>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index bb72375..4a913c8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -57,10 +58,12 @@
import org.robolectric.shadows.ShadowSettings;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {UtilsTest.ShadowLocationManager.class})
+@Config(shadows = {UtilsTest.ShadowSecure.class, UtilsTest.ShadowLocationManager.class})
public class UtilsTest {
private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100};
private static final String TAG = "UtilsTest";
@@ -91,7 +94,7 @@
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager);
when(mContext.getSystemService(UsbManager.class)).thenReturn(mUsbManager);
- ShadowSettings.ShadowSecure.reset();
+ ShadowSecure.reset();
mAudioManager = mContext.getSystemService(AudioManager.class);
}
@@ -108,16 +111,15 @@
Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.LOCATION_CHANGER,
- Settings.Secure.LOCATION_CHANGER_UNKNOWN)).isEqualTo(
- Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
+ Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
+ .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
}
@Test
public void testFormatPercentage_RoundTrue_RoundUpIfPossible() {
- final String[] expectedPercentages =
- {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1, PERCENTAGE_1, PERCENTAGE_49,
- PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50, PERCENTAGE_100};
+ final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1,
+ PERCENTAGE_1, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_50,
+ PERCENTAGE_100};
for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) {
final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], true);
@@ -127,9 +129,9 @@
@Test
public void testFormatPercentage_RoundFalse_NoRound() {
- final String[] expectedPercentages =
- {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_49,
- PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50, PERCENTAGE_100};
+ final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_0,
+ PERCENTAGE_0, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_49, PERCENTAGE_50,
+ PERCENTAGE_100};
for (int i = 0, size = TEST_PERCENTAGES.length; i < size; i++) {
final String percentage = Utils.formatPercentage(TEST_PERCENTAGES[i], false);
@@ -141,7 +143,12 @@
public void testGetDefaultStorageManagerDaysToRetain_storageManagerDaysToRetainUsesResources() {
Resources resources = mock(Resources.class);
when(resources.getInteger(
- eq(com.android.internal.R.integer.config_storageManagerDaystoRetainDefault)))
+ eq(
+ com.android
+ .internal
+ .R
+ .integer
+ .config_storageManagerDaystoRetainDefault)))
.thenReturn(60);
assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60);
}
@@ -156,6 +163,31 @@
return intent -> TextUtils.equals(expected, intent.getAction());
}
+ @Implements(value = Settings.Secure.class)
+ public static class ShadowSecure extends ShadowSettings.ShadowSecure {
+ private static Map<String, Integer> map = new HashMap<>();
+
+ @Implementation
+ public static boolean putIntForUser(ContentResolver cr, String name, int value,
+ int userHandle) {
+ map.put(name, value);
+ return true;
+ }
+
+ @Implementation
+ public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+ if (map.containsKey(name)) {
+ return map.get(name);
+ } else {
+ return def;
+ }
+ }
+
+ public static void reset() {
+ map.clear();
+ }
+ }
+
@Implements(value = LocationManager.class)
public static class ShadowLocationManager {
@@ -305,8 +337,9 @@
@Test
public void getBatteryStatus_statusIsFull_returnFullString() {
- final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra(
- BatteryManager.EXTRA_SCALE, 100);
+ final Intent intent = new Intent()
+ .putExtra(BatteryManager.EXTRA_LEVEL, 100)
+ .putExtra(BatteryManager.EXTRA_SCALE, 100);
final Resources resources = mContext.getResources();
assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo(
@@ -315,8 +348,9 @@
@Test
public void getBatteryStatus_statusIsFullAndUseCompactStatus_returnFullyChargedString() {
- final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100).putExtra(
- BatteryManager.EXTRA_SCALE, 100);
+ final Intent intent = new Intent()
+ .putExtra(BatteryManager.EXTRA_LEVEL, 100)
+ .putExtra(BatteryManager.EXTRA_SCALE, 100);
final Resources resources = mContext.getResources();
assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo(
@@ -482,6 +516,7 @@
when(mUsbPort.getStatus()).thenReturn(mUsbPortStatus);
when(mUsbPort.supportsComplianceWarnings()).thenReturn(true);
when(mUsbPortStatus.isConnected()).thenReturn(true);
- when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[]{complianceWarningType});
+ when(mUsbPortStatus.getComplianceWarnings())
+ .thenReturn(new int[]{complianceWarningType});
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
index 3de8446..44fdaec 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/accessibility/AccessibilityUtilsTest.java
@@ -23,17 +23,13 @@
import android.os.UserHandle;
import android.provider.Settings;
-import com.android.settingslib.testutils.shadow.ShadowSecure;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowSecure.class})
public class AccessibilityUtilsTest {
private Context mContext;
@@ -50,7 +46,7 @@
@Test
public void getEnabledServicesFromSettings_badFormat_emptyResult() {
- ShadowSecure.putStringForUser(
+ Settings.Secure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
":",
UserHandle.myUserId());
@@ -61,7 +57,7 @@
@Test
public void getEnabledServicesFromSettings_1Service_1result() {
final ComponentName cn = new ComponentName("pkg", "serv");
- ShadowSecure.putStringForUser(
+ Settings.Secure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
cn.flattenToString() + ":",
UserHandle.myUserId());
@@ -74,7 +70,7 @@
public void getEnabledServicesFromSettings_2Services_2results() {
final ComponentName cn1 = new ComponentName("pkg", "serv");
final ComponentName cn2 = new ComponentName("pkg", "serv2");
- ShadowSecure.putStringForUser(
+ Settings.Secure.putStringForUser(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
cn1.flattenToString() + ":" + cn2.flattenToString(),
UserHandle.myUserId());
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
index f9505dd..cb62a73 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/RecentAppOpsAccessesTest.java
@@ -37,8 +37,6 @@
import android.os.UserManager;
import android.util.LongSparseArray;
-import com.android.settingslib.testutils.shadow.ShadowPermissionChecker;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,6 +45,7 @@
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowPermissionChecker;
import java.time.Clock;
import java.util.ArrayList;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index a2e8c59..dd8d54a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -38,7 +38,6 @@
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.LooperMode;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
@@ -168,7 +167,6 @@
}
@Test
- @LooperMode(LooperMode.Mode.PAUSED)
public void getAttribution_notSet_shouldReturnUnknown() {
final Activity activity = Robolectric.setupActivity(Activity.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
index 25833b3..d67d44b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SettingsJankMonitorTest.java
@@ -36,7 +36,6 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.jank.InteractionJankMonitor.CujType;
-import com.android.settingslib.testutils.OverpoweredReflectionHelper;
import com.android.settingslib.testutils.shadow.ShadowInteractionJankMonitor;
import org.junit.Before;
@@ -52,6 +51,7 @@
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
+import org.robolectric.util.ReflectionHelpers;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -83,10 +83,8 @@
public void setUp() {
ShadowInteractionJankMonitor.reset();
when(ShadowInteractionJankMonitor.MOCK_INSTANCE.begin(any())).thenReturn(true);
- OverpoweredReflectionHelper
- .setStaticField(SettingsJankMonitor.class,
- "scheduledExecutorService",
- mScheduledExecutorService);
+ ReflectionHelpers.setStaticField(SettingsJankMonitor.class, "scheduledExecutorService",
+ mScheduledExecutorService);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
index 471dac0..cf702b53 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/HideNonSystemOverlayMixinTest.java
@@ -37,10 +37,8 @@
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
-import org.robolectric.annotation.LooperMode;
@RunWith(RobolectricTestRunner.class)
-@LooperMode(LooperMode.Mode.PAUSED)
public class HideNonSystemOverlayMixinTest {
private ActivityController<TestActivity> mActivityController;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
index b009abd..3475ff7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/DevelopmentSettingsEnablerTest.java
@@ -22,14 +22,13 @@
import android.os.UserManager;
import android.provider.Settings;
-import com.android.settingslib.testutils.shadow.ShadowUserManager;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowUserManager;
@RunWith(RobolectricTestRunner.class)
public class DevelopmentSettingsEnablerTest {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
index 0cabab2..8e33ca3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -21,7 +21,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.LooperMode;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
@@ -270,7 +269,6 @@
}
@Test
- @LooperMode(LooperMode.Mode.PAUSED)
public void testGenerateHtmlWithCustomHeading() throws Exception {
List<File> xmlFiles = new ArrayList<>();
Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>();
@@ -294,7 +292,6 @@
}
@Test
- @LooperMode(LooperMode.Mode.PAUSED)
public void testGenerateNewHtmlWithCustomHeading() throws Exception {
List<File> xmlFiles = new ArrayList<>();
Map<String, Map<String, Set<String>>> fileNameToLibraryToContentIdMap = new HashMap<>();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
index 19a3db2..a072c17 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
@@ -65,8 +65,7 @@
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mInfoMediaDevice = new InfoMediaDevice(mContext, mRouterManager, mRouteInfo,
- TEST_PACKAGE_NAME);
+ mInfoMediaDevice = new InfoMediaDevice(mContext, mRouteInfo, TEST_PACKAGE_NAME);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index ee68fc2..45b5de4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -547,8 +547,7 @@
@Test
public void connectDeviceWithoutPackageName_noSession_returnFalse() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
- final MediaDevice device = new InfoMediaDevice(mContext, mInfoMediaManager.mRouterManager,
- info, TEST_PACKAGE_NAME);
+ final MediaDevice device = new InfoMediaDevice(mContext, info, TEST_PACKAGE_NAME);
final List<RoutingSessionInfo> infos = new ArrayList<>();
@@ -624,9 +623,7 @@
routingSessionInfos.add(info);
final MediaRoute2Info route2Info = mock(MediaRoute2Info.class);
- final MediaDevice device =
- new InfoMediaDevice(mContext, mInfoMediaManager.mRouterManager, route2Info,
- TEST_PACKAGE_NAME);
+ final MediaDevice device = new InfoMediaDevice(mContext, route2Info, TEST_PACKAGE_NAME);
final List<String> list = new ArrayList<>();
list.add(TEST_ID);
@@ -647,9 +644,7 @@
routingSessionInfos.add(info);
final MediaRoute2Info route2Info = mock(MediaRoute2Info.class);
- final MediaDevice device =
- new InfoMediaDevice(mContext, mInfoMediaManager.mRouterManager, route2Info,
- TEST_PACKAGE_NAME);
+ final MediaDevice device = new InfoMediaDevice(mContext, route2Info, TEST_PACKAGE_NAME);
final List<String> list = new ArrayList<>();
list.add("fake_id");
@@ -679,9 +674,7 @@
routingSessionInfos.add(info);
final MediaRoute2Info route2Info = mock(MediaRoute2Info.class);
- final MediaDevice device =
- new InfoMediaDevice(mContext, mInfoMediaManager.mRouterManager, route2Info,
- TEST_PACKAGE_NAME);
+ final MediaDevice device = new InfoMediaDevice(mContext, route2Info, TEST_PACKAGE_NAME);
final List<String> list = new ArrayList<>();
list.add(TEST_ID);
@@ -702,9 +695,7 @@
routingSessionInfos.add(info);
final MediaRoute2Info route2Info = mock(MediaRoute2Info.class);
- final MediaDevice device =
- new InfoMediaDevice(mContext, mInfoMediaManager.mRouterManager, route2Info,
- TEST_PACKAGE_NAME);
+ final MediaDevice device = new InfoMediaDevice(mContext, route2Info, TEST_PACKAGE_NAME);
final List<String> list = new ArrayList<>();
list.add("fake_id");
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 93c6a2f..d6c33ff 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -116,10 +116,8 @@
when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
- mInfoMediaDevice1 = spy(new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo1,
- TEST_PACKAGE_NAME));
- mInfoMediaDevice2 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo2,
- TEST_PACKAGE_NAME);
+ mInfoMediaDevice1 = spy(new InfoMediaDevice(mContext, mRouteInfo1, TEST_PACKAGE_NAME));
+ mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2, TEST_PACKAGE_NAME);
mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
mInfoMediaManager, "com.test.packagename");
mLocalMediaManager.mAudioManager = mAudioManager;
@@ -150,7 +148,7 @@
assertThat(mLocalMediaManager.connectDevice(device)).isTrue();
verify(currentDevice).disconnect();
- verify(device).connect();
+ verify(mInfoMediaManager).connectToDevice(device);
}
@Test
@@ -508,7 +506,7 @@
devices.add(currentDevice);
mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
- verify(mInfoMediaDevice1).connect();
+ verify(mInfoMediaManager).connectToDevice(mInfoMediaDevice1);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index f22e090..18055d9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -26,14 +26,12 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.media.MediaRoute2Info;
-import android.media.MediaRouter2Manager;
import android.media.NearbyDevice;
import android.media.RouteListingPreference;
import android.os.Parcel;
@@ -111,9 +109,6 @@
private A2dpProfile mA2dpProfile;
@Mock
private BluetoothDevice mDevice;
- @Mock
- private MediaRouter2Manager mMediaRouter2Manager;
-
private RouteListingPreference.Item mItem;
private BluetoothMediaDevice mBluetoothMediaDevice1;
@@ -175,23 +170,18 @@
when(mA2dpProfile.getActiveDevice()).thenReturn(mDevice);
mBluetoothMediaDevice1 =
- new BluetoothMediaDevice(mContext, mCachedDevice1, mMediaRouter2Manager,
- mBluetoothRouteInfo1, TEST_PACKAGE_NAME);
+ new BluetoothMediaDevice(
+ mContext, mCachedDevice1, mBluetoothRouteInfo1, TEST_PACKAGE_NAME);
mBluetoothMediaDevice2 =
- new BluetoothMediaDevice(mContext, mCachedDevice2, mMediaRouter2Manager,
- mBluetoothRouteInfo2, TEST_PACKAGE_NAME);
+ new BluetoothMediaDevice(
+ mContext, mCachedDevice2, mBluetoothRouteInfo2, TEST_PACKAGE_NAME);
mBluetoothMediaDevice3 =
- new BluetoothMediaDevice(mContext, mCachedDevice3, mMediaRouter2Manager,
- mBluetoothRouteInfo3, TEST_PACKAGE_NAME);
- mInfoMediaDevice1 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo1,
- TEST_PACKAGE_NAME);
- mInfoMediaDevice2 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo2,
- TEST_PACKAGE_NAME);
- mInfoMediaDevice3 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo3,
- TEST_PACKAGE_NAME);
- mPhoneMediaDevice =
- new PhoneMediaDevice(mContext, mMediaRouter2Manager, mPhoneRouteInfo,
- TEST_PACKAGE_NAME);
+ new BluetoothMediaDevice(
+ mContext, mCachedDevice3, mBluetoothRouteInfo3, TEST_PACKAGE_NAME);
+ mInfoMediaDevice1 = new InfoMediaDevice(mContext, mRouteInfo1, TEST_PACKAGE_NAME);
+ mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2, TEST_PACKAGE_NAME);
+ mInfoMediaDevice3 = new InfoMediaDevice(mContext, mRouteInfo3, TEST_PACKAGE_NAME);
+ mPhoneMediaDevice = new PhoneMediaDevice(mContext, mPhoneRouteInfo, TEST_PACKAGE_NAME);
}
@Test
@@ -257,7 +247,7 @@
public void compareTo_lastSelected_others_lastSelectedFirst() {
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mBluetoothMediaDevice2);
- mBluetoothMediaDevice2.connect();
+ mBluetoothMediaDevice2.setConnectedRecord();
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
Collections.sort(mMediaDevices, COMPARATOR);
@@ -268,9 +258,9 @@
public void compareTo_connectionRecord_sortByRecord() {
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mBluetoothMediaDevice2);
- mBluetoothMediaDevice1.connect();
- mBluetoothMediaDevice2.connect();
- mBluetoothMediaDevice2.connect();
+ mBluetoothMediaDevice1.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
// Reset last selected record
ConnectionRecordManager.getInstance().setConnectionRecord(mContext, null, 0);
@@ -287,9 +277,9 @@
mMediaDevices.add(mBluetoothMediaDevice2);
when(mCachedDevice2.isConnected()).thenReturn(false);
- mBluetoothMediaDevice1.connect();
- mBluetoothMediaDevice2.connect();
- mBluetoothMediaDevice2.connect();
+ mBluetoothMediaDevice1.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
// Reset last selected record
ConnectionRecordManager.getInstance().setConnectionRecord(mContext, null, 0);
@@ -325,8 +315,8 @@
final MediaRoute2Info phoneRouteInfo = mock(MediaRoute2Info.class);
when(phoneRouteInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
- final PhoneMediaDevice phoneMediaDevice = new PhoneMediaDevice(mContext,
- mMediaRouter2Manager, phoneRouteInfo, TEST_PACKAGE_NAME);
+ final PhoneMediaDevice phoneMediaDevice =
+ new PhoneMediaDevice(mContext, phoneRouteInfo, TEST_PACKAGE_NAME);
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(phoneMediaDevice);
@@ -341,8 +331,8 @@
final MediaRoute2Info phoneRouteInfo = mock(MediaRoute2Info.class);
when(phoneRouteInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
- final PhoneMediaDevice phoneMediaDevice = new PhoneMediaDevice(mContext,
- mMediaRouter2Manager, phoneRouteInfo, TEST_PACKAGE_NAME);
+ final PhoneMediaDevice phoneMediaDevice =
+ new PhoneMediaDevice(mContext, phoneRouteInfo, TEST_PACKAGE_NAME);
mMediaDevices.add(mInfoMediaDevice1);
mMediaDevices.add(phoneMediaDevice);
@@ -403,13 +393,13 @@
mMediaDevices.add(mInfoMediaDevice2);
mMediaDevices.add(mInfoMediaDevice3);
mMediaDevices.add(mPhoneMediaDevice);
- mBluetoothMediaDevice3.connect();
- mBluetoothMediaDevice2.connect();
- mBluetoothMediaDevice2.connect();
- mInfoMediaDevice3.connect();
- mInfoMediaDevice2.connect();
- mInfoMediaDevice2.connect();
- mInfoMediaDevice1.connect();
+ mBluetoothMediaDevice3.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mInfoMediaDevice3.setConnectedRecord();
+ mInfoMediaDevice2.setConnectedRecord();
+ mInfoMediaDevice2.setConnectedRecord();
+ mInfoMediaDevice1.setConnectedRecord();
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
@@ -443,15 +433,15 @@
mMediaDevices.add(mInfoMediaDevice2);
mMediaDevices.add(mInfoMediaDevice3);
mMediaDevices.add(mPhoneMediaDevice);
- mBluetoothMediaDevice3.connect();
- mBluetoothMediaDevice2.connect();
- mBluetoothMediaDevice2.connect();
- mBluetoothMediaDevice2.connect();
- mBluetoothMediaDevice2.connect();
- mInfoMediaDevice3.connect();
- mInfoMediaDevice2.connect();
- mInfoMediaDevice2.connect();
- mInfoMediaDevice1.connect();
+ mBluetoothMediaDevice3.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mBluetoothMediaDevice2.setConnectedRecord();
+ mInfoMediaDevice3.setConnectedRecord();
+ mInfoMediaDevice2.setConnectedRecord();
+ mInfoMediaDevice2.setConnectedRecord();
+ mInfoMediaDevice1.setConnectedRecord();
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
@@ -464,13 +454,6 @@
}
@Test
- public void connect_shouldSelectRoute() {
- mInfoMediaDevice1.connect();
-
- verify(mMediaRouter2Manager).transfer(TEST_PACKAGE_NAME, mRouteInfo1);
- }
-
- @Test
public void getClientPackageName_returnPackageName() {
when(mRouteInfo1.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
@@ -498,8 +481,9 @@
@Test
public void getFeatures_noRouteInfo_returnEmptyList() {
- mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1,
- mMediaRouter2Manager, null /* MediaRoute2Info */, TEST_PACKAGE_NAME);
+ mBluetoothMediaDevice1 =
+ new BluetoothMediaDevice(
+ mContext, mCachedDevice1, null /* MediaRoute2Info */, TEST_PACKAGE_NAME);
assertThat(mBluetoothMediaDevice1.getFeatures().size()).isEqualTo(0);
}
@@ -509,11 +493,15 @@
mItem = new RouteListingPreference.Item.Builder(DEVICE_ADDRESS_1)
.setSelectionBehavior(SELECTION_BEHAVIOR_GO_TO_APP)
.build();
- mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1,
- mMediaRouter2Manager, null /* MediaRoute2Info */, TEST_PACKAGE_NAME, mItem);
+ mBluetoothMediaDevice1 =
+ new BluetoothMediaDevice(
+ mContext,
+ mCachedDevice1,
+ null /* MediaRoute2Info */,
+ TEST_PACKAGE_NAME,
+ mItem);
mPhoneMediaDevice =
- new PhoneMediaDevice(mContext, mMediaRouter2Manager, mPhoneRouteInfo,
- TEST_PACKAGE_NAME, mItem);
+ new PhoneMediaDevice(mContext, mPhoneRouteInfo, TEST_PACKAGE_NAME, mItem);
assertThat(mBluetoothMediaDevice1.getSelectionBehavior()).isEqualTo(
SELECTION_BEHAVIOR_TRANSFER);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 00d1f76..1746bef 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -56,8 +56,7 @@
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mPhoneMediaDevice =
- new PhoneMediaDevice(mContext, null, mInfo, null);
+ mPhoneMediaDevice = new PhoneMediaDevice(mContext, mInfo, null);
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java
deleted file mode 100644
index 9e9725f..0000000
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-@LooperMode(LooperMode.Mode.LEGACY)
-package com.android.settingslib;
-
-import org.robolectric.annotation.LooperMode;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
index faec02f7..d41d511 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AnimatedImageViewTest.java
@@ -27,7 +27,6 @@
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.LooperMode;
@RunWith(RobolectricTestRunner.class)
public class AnimatedImageViewTest {
@@ -41,7 +40,6 @@
}
@Test
- @LooperMode(LooperMode.Mode.PAUSED)
public void testAnimation_ViewVisible_AnimationRunning() {
mAnimatedImageView.setVisibility(View.VISIBLE);
mAnimatedImageView.setAnimating(true);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
index 0d88913..0a48f19 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BannerMessagePreferenceTest.java
@@ -41,8 +41,6 @@
import androidx.preference.PreferenceViewHolder;
import androidx.preference.R;
-import com.android.settingslib.testutils.OverpoweredReflectionHelper;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -504,18 +502,14 @@
private void assumeAndroidR() {
ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", 30);
ReflectionHelpers.setStaticField(Build.VERSION.class, "CODENAME", "R");
- OverpoweredReflectionHelper
- .setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", false);
+ ReflectionHelpers.setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", false);
// Reset view holder to use correct layout.
}
-
-
private void assumeAndroidS() {
ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", 31);
ReflectionHelpers.setStaticField(Build.VERSION.class, "CODENAME", "S");
- OverpoweredReflectionHelper
- .setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", true);
+ ReflectionHelpers.setStaticField(BannerMessagePreference.class, "IS_AT_LEAST_S", true);
// Re-inflate view to update layout.
setUpViewHolder();
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java
deleted file mode 100644
index 4fcc5a1..0000000
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/OverpoweredReflectionHelper.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.testutils;
-
-import org.robolectric.util.ReflectionHelpers;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
-public class OverpoweredReflectionHelper extends ReflectionHelpers {
-
- /**
- * Robolectric upstream does not rely on or encourage this behaviour.
- *
- * @param field
- */
- private static void makeFieldVeryAccessible(Field field) {
- field.setAccessible(true);
- // remove 'final' modifier if present
- if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
- Field modifiersField = getModifiersField();
- modifiersField.setAccessible(true);
- try {
- modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
- } catch (IllegalAccessException e) {
-
- throw new AssertionError(e);
- }
- }
- }
-
- private static Field getModifiersField() {
- try {
- return Field.class.getDeclaredField("modifiers");
- } catch (NoSuchFieldException e) {
- try {
- Method getFieldsMethod =
- Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
- getFieldsMethod.setAccessible(true);
- Field[] fields = (Field[]) getFieldsMethod.invoke(Field.class, false);
- for (Field modifiersField : fields) {
- if ("modifiers".equals(modifiersField.getName())) {
- return modifiersField;
- }
- }
- } catch (ReflectiveOperationException innerE) {
- throw new AssertionError(innerE);
- }
- }
- throw new AssertionError();
- }
-
- /**
- * Reflectively set the value of a static field.
- *
- * @param field Field object.
- * @param fieldNewValue The new value.
- */
- public static void setStaticField(Field field, Object fieldNewValue) {
- try {
- makeFieldVeryAccessible(field);
- field.setAccessible(true);
- field.set(null, fieldNewValue);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Reflectively set the value of a static field.
- *
- * @param clazz Target class.
- * @param fieldName The field name.
- * @param fieldNewValue The new value.
- */
- public static void setStaticField(Class<?> clazz, String fieldName, Object fieldNewValue) {
- try {
- setStaticField(clazz.getDeclaredField(fieldName), fieldNewValue);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
index 0b9ba8d..924eb04 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowActivityManager.java
@@ -16,27 +16,23 @@
package com.android.settingslib.testutils.shadow;
-import static android.os.Build.VERSION_CODES.O;
-
import android.app.ActivityManager;
-import android.app.IActivityManager;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.shadow.api.Shadow;
-import org.robolectric.util.ReflectionHelpers;
@Implements(ActivityManager.class)
public class ShadowActivityManager {
private static int sCurrentUserId = 0;
- private static int sUserSwitchedTo = -1;
+ private int mUserSwitchedTo = -1;
@Resetter
- public static void reset() {
+ public void reset() {
sCurrentUserId = 0;
- sUserSwitchedTo = 0;
+ mUserSwitchedTo = 0;
}
@Implementation
@@ -46,21 +42,16 @@
@Implementation
protected boolean switchUser(int userId) {
- sUserSwitchedTo = userId;
+ mUserSwitchedTo = userId;
return true;
}
- @Implementation(minSdk = O)
- protected static IActivityManager getService() {
- return ReflectionHelpers.createNullProxy(IActivityManager.class);
- }
-
public boolean getSwitchUserCalled() {
- return sUserSwitchedTo != -1;
+ return mUserSwitchedTo != -1;
}
public int getUserSwitchedTo() {
- return sUserSwitchedTo;
+ return mUserSwitchedTo;
}
public static void setCurrentUser(int userId) {
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
index bbfdb7f..2c0792f 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
@@ -29,7 +29,7 @@
private static String sDefaultDialer;
@Resetter
- public static void reset() {
+ public void reset() {
sDefaultDialer = null;
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java
deleted file mode 100644
index fae3aea..0000000
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowPermissionChecker.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.testutils.shadow;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.content.PermissionChecker;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-import java.util.HashMap;
-import java.util.Map;
-/** Shadow class of {@link PermissionChecker}. */
-@Implements(PermissionChecker.class)
-public class ShadowPermissionChecker {
- private static final Map<String, Map<String, Integer>> RESULTS = new HashMap<>();
- /** Set the result of permission check for a specific permission. */
- public static void setResult(String packageName, String permission, int result) {
- if (!RESULTS.containsKey(packageName)) {
- RESULTS.put(packageName, new HashMap<>());
- }
- RESULTS.get(packageName).put(permission, result);
- }
- /** Check the permission of calling package. */
- @Implementation
- public static int checkCallingPermissionForDataDelivery(
- Context context,
- String permission,
- String packageName,
- String attributionTag,
- String message) {
- return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
- ? RESULTS.get(packageName).get(permission)
- : PermissionChecker.checkCallingPermissionForDataDelivery(
- context, permission, packageName, attributionTag, message);
- }
- /** Check general permission. */
- @Implementation
- public static int checkPermissionForDataDelivery(
- Context context,
- String permission,
- int pid,
- int uid,
- String packageName,
- String attributionTag,
- String message) {
- return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
- ? RESULTS.get(packageName).get(permission)
- : PermissionChecker.checkPermissionForDataDelivery(
- context, permission, pid, uid, packageName, attributionTag, message);
- }
- /** Check general permission. */
- @Implementation
- public static int checkPermissionForPreflight(@NonNull Context context,
- @NonNull String permission, int pid, int uid, @Nullable String packageName) {
- return checkPermissionForPreflight(context, permission, new AttributionSource(
- uid, packageName, null /*attributionTag*/));
- }
- /** Check general permission. */
- @Implementation
- public static int checkPermissionForPreflight(@NonNull Context context,
- @NonNull String permission, @NonNull AttributionSource attributionSource) {
- final String packageName = attributionSource.getPackageName();
- return RESULTS.containsKey(packageName) && RESULTS.get(packageName).containsKey(permission)
- ? RESULTS.get(packageName).get(permission)
- : PermissionChecker.checkPermissionForPreflight(
- context, permission, attributionSource);
- }
-}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java
deleted file mode 100644
index 70ebc67..0000000
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSecure.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.testutils.shadow;
-
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
-
-import android.content.ContentResolver;
-import android.provider.Settings;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowSettings;
-
-@Implements(value = Settings.Secure.class)
-public class ShadowSecure extends ShadowSettings.ShadowSecure {
- @Implementation(minSdk = JELLY_BEAN_MR1)
- public static boolean putStringForUser(ContentResolver cr, String name, String value,
- int userHandle) {
- return putString(cr, name, value);
- }
-}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
index 5ac0a87..381d072 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
@@ -31,7 +31,7 @@
private static ComponentName sDefaultSmsApplication;
@Resetter
- public static void reset() {
+ public void reset() {
sDefaultSmsApplication = null;
}
diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index 60d7721..ca1eefc 100644
--- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -16,28 +16,20 @@
package com.android.settingslib.testutils.shadow;
-import static android.os.Build.VERSION_CODES.N_MR1;
-
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.content.pm.UserProperties;
-import android.os.UserHandle;
import android.os.UserManager;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowBuild;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
@Implements(value = UserManager.class)
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
private List<UserInfo> mUserInfos = addProfile(0, "Owner");
- private final Map<Integer, UserProperties> mUserPropertiesMap = new HashMap<>();
@Implementation
protected static UserManager get(Context context) {
@@ -70,37 +62,4 @@
protected List<UserInfo> getProfiles(@UserIdInt int userHandle) {
return getProfiles();
}
-
- /**
- * @return {@code false} by default, or the value specified via {@link #setIsAdminUser(boolean)}
- */
- @Implementation(minSdk = N_MR1)
- public boolean isAdminUser() {
- return getUserInfo(UserHandle.myUserId()).isAdmin();
- }
-
- /**
- * Sets that the current user is an admin user; controls the return value of
- * {@link UserManager#isAdminUser}.
- */
- public void setIsAdminUser(boolean isAdminUser) {
- UserInfo userInfo = getUserInfo(UserHandle.myUserId());
- if (isAdminUser) {
- userInfo.flags |= UserInfo.FLAG_ADMIN;
- } else {
- userInfo.flags &= ~UserInfo.FLAG_ADMIN;
- }
- }
-
- public void setupUserProperty(int userId, int showInSettings) {
- UserProperties userProperties = new UserProperties(new UserProperties.Builder()
- .setShowInSettings(showInSettings).build());
- mUserPropertiesMap.putIfAbsent(userId, userProperties);
- }
-
- @Implementation(minSdk = ShadowBuild.UPSIDE_DOWN_CAKE)
- protected UserProperties getUserProperties(UserHandle user) {
- return mUserPropertiesMap.getOrDefault(user.getIdentifier(),
- new UserProperties(new UserProperties.Builder().build()));
- }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 657d691..00f2d0e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -75,6 +75,15 @@
}
}
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final IContentProvider iprovider = mProvider.getIContentProvider();
+ pw.println("device config properties:");
+ for (String line : MyShellCommand.listAll(iprovider)) {
+ pw.println(line);
+ }
+ }
+
private void callUpdableDeviceConfigShellCommandHandler(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
int result = -1;
@@ -111,6 +120,31 @@
mProvider = provider;
}
+ public static List<String> listAll(IContentProvider provider) {
+ final ArrayList<String> lines = new ArrayList<>();
+
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ Bundle b = provider.call(new AttributionSource(Process.myUid(),
+ resolveCallingPackage(), null), Settings.AUTHORITY,
+ Settings.CALL_METHOD_LIST_CONFIG, null, args);
+ if (b != null) {
+ Map<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
+ for (String key : flagsToValues.keySet()) {
+ lines.add(key + "=" + flagsToValues.get(key));
+ }
+ }
+
+ Collections.sort(lines);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ return lines;
+ }
+
@SuppressLint("AndroidFrameworkRequiresPermission")
@Override
public int onCommand(String cmd) {
@@ -391,31 +425,6 @@
return success;
}
- private List<String> listAll(IContentProvider provider) {
- final ArrayList<String> lines = new ArrayList<>();
-
- try {
- Bundle args = new Bundle();
- args.putInt(Settings.CALL_METHOD_USER_KEY,
- ActivityManager.getService().getCurrentUser().id);
- Bundle b = provider.call(new AttributionSource(Process.myUid(),
- resolveCallingPackage(), null), Settings.AUTHORITY,
- Settings.CALL_METHOD_LIST_CONFIG, null, args);
- if (b != null) {
- Map<String, String> flagsToValues =
- (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
- for (String key : flagsToValues.keySet()) {
- lines.add(key + "=" + flagsToValues.get(key));
- }
- }
-
- Collections.sort(lines);
- } catch (RemoteException e) {
- throw new RuntimeException("Failed in IPC", e);
- }
- return lines;
- }
-
private static String resolveCallingPackage() {
switch (Binder.getCallingUid()) {
case Process.ROOT_UID: {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1784e48..7a60507 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -520,6 +520,13 @@
break;
}
+ case Settings.CALL_METHOD_RESET_SYSTEM: {
+ final int mode = getResetModeEnforcingPermission(args);
+ String tag = getSettingTag(args);
+ resetSystemSetting(requestingUserId, mode, tag);
+ break;
+ }
+
case Settings.CALL_METHOD_DELETE_CONFIG: {
int rows = deleteConfigSetting(name) ? 1 : 0;
Bundle result = new Bundle();
@@ -1875,8 +1882,8 @@
+ requestingUserId + ")");
}
- return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT,
- overrideableByRestore);
+ return mutateSystemSetting(name, value, /* tag= */ null, requestingUserId,
+ MUTATION_OPERATION_INSERT, /* mode= */ 0, overrideableByRestore);
}
private boolean deleteSystemSetting(String name, int requestingUserId) {
@@ -1896,15 +1903,25 @@
return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_UPDATE);
}
+ private void resetSystemSetting(int requestingUserId, int mode, String tag) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "resetSystemSetting(" + requestingUserId + ", "
+ + mode + ", " + tag + ")");
+ }
+
+ mutateSystemSetting(null, null, tag, requestingUserId, MUTATION_OPERATION_RESET, mode,
+ false);
+ }
+
private boolean mutateSystemSetting(String name, String value, int runAsUserId, int operation) {
// overrideableByRestore = false as by default settings values shouldn't be overrideable by
// restore.
- return mutateSystemSetting(name, value, runAsUserId, operation,
- /* overrideableByRestore */ false);
+ return mutateSystemSetting(name, value, /* tag= */ null, runAsUserId, operation,
+ /* mode= */ 0, /* overrideableByRestore */ false);
}
- private boolean mutateSystemSetting(String name, String value, int runAsUserId, int operation,
- boolean overrideableByRestore) {
+ private boolean mutateSystemSetting(String name, String value, String tag, int runAsUserId,
+ int operation, int mode, boolean overrideableByRestore) {
final String callingPackage = getCallingPackage();
if (!hasWriteSecureSettingsPermission()) {
// If the caller doesn't hold WRITE_SECURE_SETTINGS, we verify whether this
@@ -1976,6 +1993,12 @@
owningUserId, name, value, null, false, callingPackage,
false, null);
}
+
+ case MUTATION_OPERATION_RESET: {
+ mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_SYSTEM,
+ UserHandle.USER_SYSTEM, callingPackage, mode, tag);
+ return true;
+ }
}
Slog.e(LOG_TAG, "Unknown operation code: " + operation);
return false;
diff --git a/packages/SoundPicker/res/values-af/strings.xml b/packages/SoundPicker/res/values-af/strings.xml
index fd857b1..7396b76 100644
--- a/packages/SoundPicker/res/values-af/strings.xml
+++ b/packages/SoundPicker/res/values-af/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Kan nie gepasmaakte luitoon byvoeg nie"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Kan nie gepasmaakte luitoon uitvee nie"</string>
<string name="app_label" msgid="3091611356093417332">"Klanke"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Die lys is leeg"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Klank"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrasie"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-am/strings.xml b/packages/SoundPicker/res/values-am/strings.xml
index 85206c0..bd1c24b 100644
--- a/packages/SoundPicker/res/values-am/strings.xml
+++ b/packages/SoundPicker/res/values-am/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"ብጁ የጥሪ ቅላጼን ማከል አልተቻለም"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ብጁ የጥሪ ቅላጼን መሰረዝ አልተቻለም"</string>
<string name="app_label" msgid="3091611356093417332">"ድምፆች"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ዝርዝሩ ባዶ ነው"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ድምፅ"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ንዝረት"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ar/strings.xml b/packages/SoundPicker/res/values-ar/strings.xml
index f8844e9..805c7cf 100644
--- a/packages/SoundPicker/res/values-ar/strings.xml
+++ b/packages/SoundPicker/res/values-ar/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"يتعذر إضافة نغمة رنين مخصصة"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"يتعذر حذف نغمة الرنين المخصصة"</string>
<string name="app_label" msgid="3091611356093417332">"الأصوات"</string>
+ <string name="empty_list" msgid="2871978423955821191">"القائمة فارغة."</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"الصوت"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"الاهتزاز"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-as/strings.xml b/packages/SoundPicker/res/values-as/strings.xml
index 5d6bc5d..0a1cd1b 100644
--- a/packages/SoundPicker/res/values-as/strings.xml
+++ b/packages/SoundPicker/res/values-as/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"নিজৰ উপযোগিতা অনুযায়ী তৈয়াৰ কৰা ৰিংট\'ন যোগ কৰিব পৰা নগ\'ল"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"নিজৰ উপযোগিতা অনুযায়ী তৈয়াৰ কৰা ৰিংট\'ন মচিব পৰা নগ\'ল"</string>
<string name="app_label" msgid="3091611356093417332">"ধ্বনিসমূহ"</string>
+ <string name="empty_list" msgid="2871978423955821191">"সূচীখন খালী আছে"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ধ্বনি"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"কম্পন"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-az/strings.xml b/packages/SoundPicker/res/values-az/strings.xml
index e32c3eb..a308329 100644
--- a/packages/SoundPicker/res/values-az/strings.xml
+++ b/packages/SoundPicker/res/values-az/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Fərdi zəng səsi əlavə etmək mümkün deyil"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Fərdi zəng səsini silmək mümkün deyil"</string>
<string name="app_label" msgid="3091611356093417332">"Səslər"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Siyahı boşdur"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Səs"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrasiya"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-b+sr+Latn/strings.xml b/packages/SoundPicker/res/values-b+sr+Latn/strings.xml
index 947c85c..2a7a196 100644
--- a/packages/SoundPicker/res/values-b+sr+Latn/strings.xml
+++ b/packages/SoundPicker/res/values-b+sr+Latn/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Dodavanje prilagođene melodije zvona nije uspelo"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Brisanje prilagođene melodije zvona nije uspelo"</string>
<string name="app_label" msgid="3091611356093417332">"Zvukovi"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Lista je prazna"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Zvuk"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibriranje"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-be/strings.xml b/packages/SoundPicker/res/values-be/strings.xml
index 6f7fc68..431a301 100644
--- a/packages/SoundPicker/res/values-be/strings.xml
+++ b/packages/SoundPicker/res/values-be/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Немагчыма дадаць карыстальніцкі рынгтон"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Немагчыма выдаліць карыстальніцкі рынгтон"</string>
<string name="app_label" msgid="3091611356093417332">"Гукі"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Спіс пусты"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Гук"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Вібрацыя"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-bg/strings.xml b/packages/SoundPicker/res/values-bg/strings.xml
index 4277d28..7447af6 100644
--- a/packages/SoundPicker/res/values-bg/strings.xml
+++ b/packages/SoundPicker/res/values-bg/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Персонализираната мелодия не може да се добави"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Персонализираната мелодия не може да се изтрие"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Списъкът е празен"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Звук"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Вибриране"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-bn/strings.xml b/packages/SoundPicker/res/values-bn/strings.xml
index 276594a..c31b36a 100644
--- a/packages/SoundPicker/res/values-bn/strings.xml
+++ b/packages/SoundPicker/res/values-bn/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"কাস্টম রিংটোন যোগ করা গেল না"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"কাস্টম রিংটোন মোছা গেল না"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"তালিকায় কিছু নেই"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"সাউন্ড"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ভাইব্রেশন"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-bs/strings.xml b/packages/SoundPicker/res/values-bs/strings.xml
index 0c8d33f..e65b90d 100644
--- a/packages/SoundPicker/res/values-bs/strings.xml
+++ b/packages/SoundPicker/res/values-bs/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nije moguće dodati prilagođenu melodiju zvona"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nije moguće izbrisati prilagođenu melodiju zvona"</string>
<string name="app_label" msgid="3091611356093417332">"Zvukovi"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Lista je prazna"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Zvuk"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibracija"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ca/strings.xml b/packages/SoundPicker/res/values-ca/strings.xml
index ed96f70..33839bc 100644
--- a/packages/SoundPicker/res/values-ca/strings.xml
+++ b/packages/SoundPicker/res/values-ca/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"No es pot afegir el so de trucada personalitzat"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"No es pot suprimir el so de trucada personalitzat"</string>
<string name="app_label" msgid="3091611356093417332">"Sons"</string>
+ <string name="empty_list" msgid="2871978423955821191">"La llista és buida"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"So"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibració"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-cs/strings.xml b/packages/SoundPicker/res/values-cs/strings.xml
index dc67c96..612a6b2 100644
--- a/packages/SoundPicker/res/values-cs/strings.xml
+++ b/packages/SoundPicker/res/values-cs/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Vlastní vyzvánění se nepodařilo přidat"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Vlastní vyzvánění se nepodařilo smazat"</string>
<string name="app_label" msgid="3091611356093417332">"Zvuky"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Seznam je prázdný"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Zvuk"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrace"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-da/strings.xml b/packages/SoundPicker/res/values-da/strings.xml
index b4437dc..56c4d23 100644
--- a/packages/SoundPicker/res/values-da/strings.xml
+++ b/packages/SoundPicker/res/values-da/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Den tilpassede ringetone kunne ikke tilføjes"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Den tilpassede ringetone kunne ikke slettes"</string>
<string name="app_label" msgid="3091611356093417332">"Lyde"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Listen er tom"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Lyd"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-de/strings.xml b/packages/SoundPicker/res/values-de/strings.xml
index 8be3aaa..b004e2a 100644
--- a/packages/SoundPicker/res/values-de/strings.xml
+++ b/packages/SoundPicker/res/values-de/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Benutzerdefinierter Klingelton konnte nicht hinzugefügt werden"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Benutzerdefinierter Klingelton konnte nicht gelöscht werden"</string>
<string name="app_label" msgid="3091611356093417332">"Töne"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Die Liste ist leer"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Ton"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-el/strings.xml b/packages/SoundPicker/res/values-el/strings.xml
index 41e9b0c..bbcb1f5 100644
--- a/packages/SoundPicker/res/values-el/strings.xml
+++ b/packages/SoundPicker/res/values-el/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Δεν είναι δυνατή η προσθήκη προσαρμοσμένου ήχου κλήσης"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Δεν είναι δυνατή η διαγραφή προσαρμοσμένου ήχου κλήσης"</string>
<string name="app_label" msgid="3091611356093417332">"Ήχοι"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Η λίστα είναι κενή"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Ήχος"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Δόνηση"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-en-rAU/strings.xml b/packages/SoundPicker/res/values-en-rAU/strings.xml
index 4c237b9..5030314 100644
--- a/packages/SoundPicker/res/values-en-rAU/strings.xml
+++ b/packages/SoundPicker/res/values-en-rAU/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add customised ringtone"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete customised ringtone"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"The list is empty"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sound"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-en-rCA/strings.xml b/packages/SoundPicker/res/values-en-rCA/strings.xml
index b0708356..d887082 100644
--- a/packages/SoundPicker/res/values-en-rCA/strings.xml
+++ b/packages/SoundPicker/res/values-en-rCA/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add custom ringtone"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete custom ringtone"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"The list is empty"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sound"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-en-rGB/strings.xml b/packages/SoundPicker/res/values-en-rGB/strings.xml
index 4c237b9..5030314 100644
--- a/packages/SoundPicker/res/values-en-rGB/strings.xml
+++ b/packages/SoundPicker/res/values-en-rGB/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add customised ringtone"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete customised ringtone"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"The list is empty"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sound"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-en-rIN/strings.xml b/packages/SoundPicker/res/values-en-rIN/strings.xml
index 4c237b9..5030314 100644
--- a/packages/SoundPicker/res/values-en-rIN/strings.xml
+++ b/packages/SoundPicker/res/values-en-rIN/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add customised ringtone"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete customised ringtone"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"The list is empty"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sound"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-en-rXC/strings.xml b/packages/SoundPicker/res/values-en-rXC/strings.xml
index 8397e0b..d26c89b 100644
--- a/packages/SoundPicker/res/values-en-rXC/strings.xml
+++ b/packages/SoundPicker/res/values-en-rXC/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add custom ringtone"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete custom ringtone"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"The list is empty"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sound"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-es-rUS/strings.xml b/packages/SoundPicker/res/values-es-rUS/strings.xml
index 5bf73b2..211bfed 100644
--- a/packages/SoundPicker/res/values-es-rUS/strings.xml
+++ b/packages/SoundPicker/res/values-es-rUS/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"No se puede agregar el tono personalizado"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"No se puede borrar el tono personalizado"</string>
<string name="app_label" msgid="3091611356093417332">"Sonidos"</string>
+ <string name="empty_list" msgid="2871978423955821191">"La lista está vacía"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sonido"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibración"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-es/strings.xml b/packages/SoundPicker/res/values-es/strings.xml
index a77f656..3fdad74 100644
--- a/packages/SoundPicker/res/values-es/strings.xml
+++ b/packages/SoundPicker/res/values-es/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"No se ha podido añadir un tono de llamada personalizado"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"No se ha podido eliminar un tono de llamada personalizado"</string>
<string name="app_label" msgid="3091611356093417332">"Sonidos"</string>
+ <string name="empty_list" msgid="2871978423955821191">"La lista está vacía"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sonido"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibración"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-et/strings.xml b/packages/SoundPicker/res/values-et/strings.xml
index fa680ac..3d9ee94 100644
--- a/packages/SoundPicker/res/values-et/strings.xml
+++ b/packages/SoundPicker/res/values-et/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Kohandatud helinat ei õnnestu lisada"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Kohandatud helinat ei õnnestu kustutada"</string>
<string name="app_label" msgid="3091611356093417332">"Helid"</string>
+ <string name="empty_list" msgid="2871978423955821191">"See loend on tühi"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Heli"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibreerimine"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-eu/strings.xml b/packages/SoundPicker/res/values-eu/strings.xml
index e8e07fe..1f929bf 100644
--- a/packages/SoundPicker/res/values-eu/strings.xml
+++ b/packages/SoundPicker/res/values-eu/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Ezin da gehitu tonu pertsonalizatua"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Ezin da ezabatu tonu pertsonalizatua"</string>
<string name="app_label" msgid="3091611356093417332">"Soinuak"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Zerrenda hutsik dago"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Soinua"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Dardara"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-fa/strings.xml b/packages/SoundPicker/res/values-fa/strings.xml
index 769d5d5..3b75ac9 100644
--- a/packages/SoundPicker/res/values-fa/strings.xml
+++ b/packages/SoundPicker/res/values-fa/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"افزودن آهنگ زنگ سفارشی ممکن نیست"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"حذف آهنگ زنگ سفارشی ممکن نیست"</string>
<string name="app_label" msgid="3091611356093417332">"صداها"</string>
+ <string name="empty_list" msgid="2871978423955821191">"فهرست خالی است"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"صدا"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"لرزش"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-fi/strings.xml b/packages/SoundPicker/res/values-fi/strings.xml
index fcda098..15bf658 100644
--- a/packages/SoundPicker/res/values-fi/strings.xml
+++ b/packages/SoundPicker/res/values-fi/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Muokatun soittoäänen lisääminen epäonnistui."</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Muokatun soittoäänen poistaminen epäonnistui."</string>
<string name="app_label" msgid="3091611356093417332">"Äänet"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Lista on tyhjä"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Ääni"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Värinä"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-fr-rCA/strings.xml b/packages/SoundPicker/res/values-fr-rCA/strings.xml
index 4d4545f..1cc170f 100644
--- a/packages/SoundPicker/res/values-fr-rCA/strings.xml
+++ b/packages/SoundPicker/res/values-fr-rCA/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Impossible d\'ajouter une sonnerie personnalisée"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Impossible de supprimer la sonnerie personnalisée"</string>
<string name="app_label" msgid="3091611356093417332">"Sons"</string>
+ <string name="empty_list" msgid="2871978423955821191">"La liste est vide"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Son"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-fr/strings.xml b/packages/SoundPicker/res/values-fr/strings.xml
index 9452e70..ade2c16 100644
--- a/packages/SoundPicker/res/values-fr/strings.xml
+++ b/packages/SoundPicker/res/values-fr/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Impossible d\'ajouter une sonnerie personnalisée"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Impossible de supprimer la sonnerie personnalisée"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"La liste est vide"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Son"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-gl/strings.xml b/packages/SoundPicker/res/values-gl/strings.xml
index 59a9d06..83f2b2e 100644
--- a/packages/SoundPicker/res/values-gl/strings.xml
+++ b/packages/SoundPicker/res/values-gl/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Non se pode engadir un ton de chamada personalizado"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Non se pode eliminar un ton de chamada personalizado"</string>
<string name="app_label" msgid="3091611356093417332">"Sons"</string>
+ <string name="empty_list" msgid="2871978423955821191">"A lista está baleira"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Son"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibración"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-gu/strings.xml b/packages/SoundPicker/res/values-gu/strings.xml
index 209769f..8207512 100644
--- a/packages/SoundPicker/res/values-gu/strings.xml
+++ b/packages/SoundPicker/res/values-gu/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"કસ્ટમ રિંગટોન ઉમેરવામાં અસમર્થ"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"કસ્ટમ રિંગટોન કાઢી નાખવામાં અસમર્થ"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"સૂચિ ખાલી છે"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"સાઉન્ડ"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"વાઇબ્રેશન"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-hi/strings.xml b/packages/SoundPicker/res/values-hi/strings.xml
index ab3b7f8..304201f 100644
--- a/packages/SoundPicker/res/values-hi/strings.xml
+++ b/packages/SoundPicker/res/values-hi/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"आपके मुताबिक रिंगटोन नहीं जोड़ी जा सकी"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"आपके मुताबिक रिंगटोन नहीं हटाई जा सकी"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"यह सूची खाली है"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"साउंड"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"वाइब्रेशन"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-hr/strings.xml b/packages/SoundPicker/res/values-hr/strings.xml
index 3adc500..642c7d5 100644
--- a/packages/SoundPicker/res/values-hr/strings.xml
+++ b/packages/SoundPicker/res/values-hr/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Dodavanje prilagođene melodije zvona nije moguće"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Brisanje prilagođene melodije zvona nije moguće"</string>
<string name="app_label" msgid="3091611356093417332">"Zvukovi"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Popis je prazan"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Zvuk"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibracija"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-hu/strings.xml b/packages/SoundPicker/res/values-hu/strings.xml
index 32d4ba9..401da84 100644
--- a/packages/SoundPicker/res/values-hu/strings.xml
+++ b/packages/SoundPicker/res/values-hu/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nem sikerült hozzáadni az egyéni csengőhangot"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nem sikerült törölni az egyéni csengőhangot"</string>
<string name="app_label" msgid="3091611356093417332">"Hangok"</string>
+ <string name="empty_list" msgid="2871978423955821191">"A lista üres"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Hang"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Rezgés"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-hy/strings.xml b/packages/SoundPicker/res/values-hy/strings.xml
index da8934f..d57345c 100644
--- a/packages/SoundPicker/res/values-hy/strings.xml
+++ b/packages/SoundPicker/res/values-hy/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Հնարավոր չէ հատուկ զանգերանգ ավելացնել"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Հնարավոր չէ ջնջել հատուկ զանգերանգը"</string>
<string name="app_label" msgid="3091611356093417332">"Ձայներ"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Ցանկը դատարկ է"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Ձայն"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Թրթռոց"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-in/strings.xml b/packages/SoundPicker/res/values-in/strings.xml
index 86dce64..518a09d 100644
--- a/packages/SoundPicker/res/values-in/strings.xml
+++ b/packages/SoundPicker/res/values-in/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Tidak dapat menambahkan nada dering khusus"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Tidak dapat menghapus nada dering khusus"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Daftar ini kosong"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Suara"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Getaran"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-is/strings.xml b/packages/SoundPicker/res/values-is/strings.xml
index d0fce78..7f05c79 100644
--- a/packages/SoundPicker/res/values-is/strings.xml
+++ b/packages/SoundPicker/res/values-is/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Get ekki bætt sérsniðnum hringitóni við"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Get ekki eytt sérsniðnum hringitóni"</string>
<string name="app_label" msgid="3091611356093417332">"Hljóð"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Listinn er auður"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Hljóð"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Titringur"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-it/strings.xml b/packages/SoundPicker/res/values-it/strings.xml
index 632cb41..e1d8e19 100644
--- a/packages/SoundPicker/res/values-it/strings.xml
+++ b/packages/SoundPicker/res/values-it/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Impossibile aggiungere suoneria personalizzata"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Impossibile eliminare suoneria personalizzata"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"L\'elenco è vuoto"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Suoneria"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrazione"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-iw/strings.xml b/packages/SoundPicker/res/values-iw/strings.xml
index 387b140..238370c9 100644
--- a/packages/SoundPicker/res/values-iw/strings.xml
+++ b/packages/SoundPicker/res/values-iw/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"לא ניתן להוסיף רינגטון מותאם אישית"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"לא ניתן למחוק רינגטון מותאם אישית"</string>
<string name="app_label" msgid="3091611356093417332">"צלילים"</string>
+ <string name="empty_list" msgid="2871978423955821191">"הרשימה ריקה"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"צליל"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"רטט"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ja/strings.xml b/packages/SoundPicker/res/values-ja/strings.xml
index 7c2aec6..408e870 100644
--- a/packages/SoundPicker/res/values-ja/strings.xml
+++ b/packages/SoundPicker/res/values-ja/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"カスタム着信音を追加できません"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"カスタム着信音を削除できません"</string>
<string name="app_label" msgid="3091611356093417332">"サウンド"</string>
+ <string name="empty_list" msgid="2871978423955821191">"このリストは空です"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"音"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"バイブレーション"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ka/strings.xml b/packages/SoundPicker/res/values-ka/strings.xml
index 1cfe240..83dfc3c 100644
--- a/packages/SoundPicker/res/values-ka/strings.xml
+++ b/packages/SoundPicker/res/values-ka/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"მორგებული ზარის დამატება შეუძლებელია"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"მორგებული ზარის წაშლა შეუძლებელია"</string>
<string name="app_label" msgid="3091611356093417332">"ხმები"</string>
+ <string name="empty_list" msgid="2871978423955821191">"სია ცარიელია"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ხმა"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ვიბრაცია"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-kk/strings.xml b/packages/SoundPicker/res/values-kk/strings.xml
index 8c4c169..1815a95 100644
--- a/packages/SoundPicker/res/values-kk/strings.xml
+++ b/packages/SoundPicker/res/values-kk/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Арнаулы рингтонды енгізу мүмкін емес"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Арнаулы рингтонды жою мүмкін емес"</string>
<string name="app_label" msgid="3091611356093417332">"Дыбыстар"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Тізім бос."</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Дыбыс"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Діріл"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-km/strings.xml b/packages/SoundPicker/res/values-km/strings.xml
index a334429..6ae048f 100644
--- a/packages/SoundPicker/res/values-km/strings.xml
+++ b/packages/SoundPicker/res/values-km/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"មិនអាចបន្ថែមសំឡេងរោទ៍ផ្ទាល់ខ្លួនបាន"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"មិនអាចលុបសំឡេងរោទ៍ផ្ទាល់ខ្លួនបានទេ"</string>
<string name="app_label" msgid="3091611356093417332">"សំឡេង"</string>
+ <string name="empty_list" msgid="2871978423955821191">"បញ្ជីគឺទទេ"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"សំឡេង"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ការញ័រ"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-kn/strings.xml b/packages/SoundPicker/res/values-kn/strings.xml
index da90ccb..c528866 100644
--- a/packages/SoundPicker/res/values-kn/strings.xml
+++ b/packages/SoundPicker/res/values-kn/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"ಕಸ್ಟಮ್ ರಿಂಗ್ಟೋನ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ಕಸ್ಟಮ್ ರಿಂಗ್ಟೋನ್ ಅಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="app_label" msgid="3091611356093417332">"ಧ್ವನಿಗಳು"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ಪಟ್ಟಿ ಖಾಲಿಯಾಗಿದೆ"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ಧ್ವನಿ"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ವೈಬ್ರೇಷನ್"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ko/strings.xml b/packages/SoundPicker/res/values-ko/strings.xml
index 70554d6..bcab6b2 100644
--- a/packages/SoundPicker/res/values-ko/strings.xml
+++ b/packages/SoundPicker/res/values-ko/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"맞춤 벨소리를 추가할 수 없습니다."</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"맞춤 벨소리를 삭제할 수 없습니다."</string>
<string name="app_label" msgid="3091611356093417332">"소리"</string>
+ <string name="empty_list" msgid="2871978423955821191">"목록이 비어 있음"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"소리"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"진동"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ky/strings.xml b/packages/SoundPicker/res/values-ky/strings.xml
index 3c95228..babd8c0 100644
--- a/packages/SoundPicker/res/values-ky/strings.xml
+++ b/packages/SoundPicker/res/values-ky/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Жеке рингтон кошулбай жатат"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Жеке рингтон жок кылынбай жатат"</string>
<string name="app_label" msgid="3091611356093417332">"Үндөр"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Тизме бош"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Үн"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Дирилдөө"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-lo/strings.xml b/packages/SoundPicker/res/values-lo/strings.xml
index 8bcae0d..5e496e8 100644
--- a/packages/SoundPicker/res/values-lo/strings.xml
+++ b/packages/SoundPicker/res/values-lo/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Unable to add custom ringtone"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Unable to delete custom ringtone"</string>
<string name="app_label" msgid="3091611356093417332">"ສຽງ"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ລາຍຊື່ຫວ່າງເປົ່າ"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ສຽງ"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ການສັ່ນເຕືອນ"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-lt/strings.xml b/packages/SoundPicker/res/values-lt/strings.xml
index c7ea369..c68cc3b 100644
--- a/packages/SoundPicker/res/values-lt/strings.xml
+++ b/packages/SoundPicker/res/values-lt/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nepavyksta pridėti tinkinto skambėjimo tono"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nepavyksta ištrinti tinkinto skambėjimo tono"</string>
<string name="app_label" msgid="3091611356093417332">"Garsai"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Sąrašas yra tuščias"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Garsas"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibravimas"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-lv/strings.xml b/packages/SoundPicker/res/values-lv/strings.xml
index 2a26289..fab7f8c 100644
--- a/packages/SoundPicker/res/values-lv/strings.xml
+++ b/packages/SoundPicker/res/values-lv/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nevar pievienot pielāgotu zvana signālu"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nevar izdzēst pielāgotu zvana signālu"</string>
<string name="app_label" msgid="3091611356093417332">"Skaņas"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Saraksts ir tukšs"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Skaņa"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrācija"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-mk/strings.xml b/packages/SoundPicker/res/values-mk/strings.xml
index 545d5ed..4f2322a 100644
--- a/packages/SoundPicker/res/values-mk/strings.xml
+++ b/packages/SoundPicker/res/values-mk/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Не може да се додаде приспособена мелодија"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Не може да се избрише приспособена мелодија"</string>
<string name="app_label" msgid="3091611356093417332">"Звуци"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Списокот е празен"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Звук"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Вибрации"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ml/strings.xml b/packages/SoundPicker/res/values-ml/strings.xml
index 21da8e8..16cf725 100644
--- a/packages/SoundPicker/res/values-ml/strings.xml
+++ b/packages/SoundPicker/res/values-ml/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"ഇഷ്ടാനുസൃത റിംഗ്ടോൺ ചേർക്കാനാവില്ല"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ഇഷ്ടാനുസൃത റിംഗ്ടോൺ ഇല്ലാതാക്കാനാവില്ല"</string>
<string name="app_label" msgid="3091611356093417332">"ശബ്ദങ്ങൾ"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ലിസ്റ്റിൽ ഒന്നുമില്ല"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ശബ്ദം"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"വൈബ്രേഷൻ"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-mn/strings.xml b/packages/SoundPicker/res/values-mn/strings.xml
index 15f7d12..6215a41 100644
--- a/packages/SoundPicker/res/values-mn/strings.xml
+++ b/packages/SoundPicker/res/values-mn/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Захиалгат хонхны ая нэмэх боломжгүй"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Захиалгат хонхны ая устгах боломжгүй"</string>
<string name="app_label" msgid="3091611356093417332">"Дуу чимээ"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Жагсаалт хоосон байна"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Дуу"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Чичиргээ"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-mr/strings.xml b/packages/SoundPicker/res/values-mr/strings.xml
index 3ddb991..fe2fe12 100644
--- a/packages/SoundPicker/res/values-mr/strings.xml
+++ b/packages/SoundPicker/res/values-mr/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"कस्टम रिंगटोन जोडण्यात अक्षम"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"कस्टम रिंगटोन हटविण्यात अक्षम"</string>
<string name="app_label" msgid="3091611356093417332">"आवाज"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ही सूची रिकामी आहे"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"आवाज"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"व्हायब्रेशन"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ms/strings.xml b/packages/SoundPicker/res/values-ms/strings.xml
index 9d87d72..5788f18 100644
--- a/packages/SoundPicker/res/values-ms/strings.xml
+++ b/packages/SoundPicker/res/values-ms/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Tidak dapat menambah nada dering tersuai"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Tidak dapat memadamkan nada dering tersuai"</string>
<string name="app_label" msgid="3091611356093417332">"Bunyi"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Senarai ini kosong"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Bunyi"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Getaran"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-my/strings.xml b/packages/SoundPicker/res/values-my/strings.xml
index 62163e9..0a1a4cf 100644
--- a/packages/SoundPicker/res/values-my/strings.xml
+++ b/packages/SoundPicker/res/values-my/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"စိတ်ကြိုက်ဖုန်းမြည်သံကို ထည့်သွင်း၍မရပါ"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"စိတ်ကြိုက်ဖုန်းမြည်သံကို ဖျက်၍မရပါ"</string>
<string name="app_label" msgid="3091611356093417332">"အသံများ"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ဤစာရင်းတွင် မည်သည့်အရာမျှမရှိပါ"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"အသံ"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"တုန်ခါမှု"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-nb/strings.xml b/packages/SoundPicker/res/values-nb/strings.xml
index e4e259a..c315801 100644
--- a/packages/SoundPicker/res/values-nb/strings.xml
+++ b/packages/SoundPicker/res/values-nb/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Kan ikke legge til egendefinert ringelyd"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Kan ikke slette egendefinert ringelyd"</string>
<string name="app_label" msgid="3091611356093417332">"Lyder"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Listen er tom"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Lyd"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrering"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ne/strings.xml b/packages/SoundPicker/res/values-ne/strings.xml
index 0a2bceb..b95b70c 100644
--- a/packages/SoundPicker/res/values-ne/strings.xml
+++ b/packages/SoundPicker/res/values-ne/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"आफू अनुकूल रिङटोन थप्न सकिएन"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"आफू अनुकूल रिङटोनलाई मेट्न सकिएन"</string>
<string name="app_label" msgid="3091611356093417332">"ध्वनिहरू"</string>
+ <string name="empty_list" msgid="2871978423955821191">"यो सूची खाली छ"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ध्वनि"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"भाइब्रेसन"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-nl/strings.xml b/packages/SoundPicker/res/values-nl/strings.xml
index 5b6fb70..192431b 100644
--- a/packages/SoundPicker/res/values-nl/strings.xml
+++ b/packages/SoundPicker/res/values-nl/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Toevoegen van aangepaste ringtone is mislukt"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Verwijderen van aangepaste ringtone is mislukt"</string>
<string name="app_label" msgid="3091611356093417332">"Geluiden"</string>
+ <string name="empty_list" msgid="2871978423955821191">"De lijst is leeg"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Geluid"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Trillen"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-or/strings.xml b/packages/SoundPicker/res/values-or/strings.xml
index 45ce594..5d82039 100644
--- a/packages/SoundPicker/res/values-or/strings.xml
+++ b/packages/SoundPicker/res/values-or/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"କଷ୍ଟମ୍ ରିଙ୍ଗଟୋନ୍ ଯୋଡ଼ିପାରିବ ନାହିଁ"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"କଷ୍ଟମ୍ ରିଙ୍ଗଟୋନ୍ ଡିଲିଟ୍ କରିପାରିବ ନାହିଁ"</string>
<string name="app_label" msgid="3091611356093417332">"ସାଉଣ୍ଡ"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ତାଲିକା ଖାଲି ଅଛି"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ସାଉଣ୍ଡ"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ଭାଇବ୍ରେସନ"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-pa/strings.xml b/packages/SoundPicker/res/values-pa/strings.xml
index 1e62f64..63ecb9d 100644
--- a/packages/SoundPicker/res/values-pa/strings.xml
+++ b/packages/SoundPicker/res/values-pa/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"ਵਿਉਂਤੀ ਰਿੰਗਟੋਨ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਦੇ ਅਯੋਗ"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ਵਿਉਂਤੀ ਰਿੰਗਟੋਨ ਨੂੰ ਮਿਟਾਉਣ ਦੇ ਅਯੋਗ"</string>
<string name="app_label" msgid="3091611356093417332">"Sounds"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ਇਹ ਸੂਚੀ ਖਾਲੀ ਹੈ"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ਅਵਾਜ਼"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"ਥਰਥਰਾਹਟ"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-pl/strings.xml b/packages/SoundPicker/res/values-pl/strings.xml
index 1b3b5c4..310f40f 100644
--- a/packages/SoundPicker/res/values-pl/strings.xml
+++ b/packages/SoundPicker/res/values-pl/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nie można dodać dzwonka niestandardowego"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nie można usunąć dzwonka niestandardowego"</string>
<string name="app_label" msgid="3091611356093417332">"Dźwięki"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Lista jest pusta"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Dźwięk"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Wibracje"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-pt-rBR/strings.xml b/packages/SoundPicker/res/values-pt-rBR/strings.xml
index 7b545e1..9f58ca0 100644
--- a/packages/SoundPicker/res/values-pt-rBR/strings.xml
+++ b/packages/SoundPicker/res/values-pt-rBR/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Não foi possível adicionar o toque personalizado"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Não foi possível excluir o toque personalizado"</string>
<string name="app_label" msgid="3091611356093417332">"Sons"</string>
+ <string name="empty_list" msgid="2871978423955821191">"A lista está vazia"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Som"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibração"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-pt-rPT/strings.xml b/packages/SoundPicker/res/values-pt-rPT/strings.xml
index 5d742f1..fd4e69f 100644
--- a/packages/SoundPicker/res/values-pt-rPT/strings.xml
+++ b/packages/SoundPicker/res/values-pt-rPT/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Não foi possível adicionar o toque personalizado"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Não foi possível eliminar o toque personalizado"</string>
<string name="app_label" msgid="3091611356093417332">"Sons"</string>
+ <string name="empty_list" msgid="2871978423955821191">"A lista está vazia"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Som"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibração"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-pt/strings.xml b/packages/SoundPicker/res/values-pt/strings.xml
index 7b545e1..9f58ca0 100644
--- a/packages/SoundPicker/res/values-pt/strings.xml
+++ b/packages/SoundPicker/res/values-pt/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Não foi possível adicionar o toque personalizado"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Não foi possível excluir o toque personalizado"</string>
<string name="app_label" msgid="3091611356093417332">"Sons"</string>
+ <string name="empty_list" msgid="2871978423955821191">"A lista está vazia"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Som"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibração"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ro/strings.xml b/packages/SoundPicker/res/values-ro/strings.xml
index 58b5aeb..08d937c 100644
--- a/packages/SoundPicker/res/values-ro/strings.xml
+++ b/packages/SoundPicker/res/values-ro/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nu se poate adăuga tonul de sonerie personalizat"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nu se poate șterge tonul de sonerie personalizat"</string>
<string name="app_label" msgid="3091611356093417332">"Sunete"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Lista este goală"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sunet"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrație"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ru/strings.xml b/packages/SoundPicker/res/values-ru/strings.xml
index 0d48ac1..be5495a 100644
--- a/packages/SoundPicker/res/values-ru/strings.xml
+++ b/packages/SoundPicker/res/values-ru/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Не удалось добавить рингтон"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Не удалось удалить рингтон"</string>
<string name="app_label" msgid="3091611356093417332">"Звуки"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Список пуст"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Звук"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Вибрация"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-si/strings.xml b/packages/SoundPicker/res/values-si/strings.xml
index 1872b6b..6ba86cb 100644
--- a/packages/SoundPicker/res/values-si/strings.xml
+++ b/packages/SoundPicker/res/values-si/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"අභිරුචි නාද රිද්මය එක් කළ නොහැකිය"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"අභිරුචි නාද රිද්මය මැකිය නොහැකිය"</string>
<string name="app_label" msgid="3091611356093417332">"ශබ්ද"</string>
+ <string name="empty_list" msgid="2871978423955821191">"ලැයිස්තුව හිස් ය"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ශබ්දය"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"කම්පනය"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-sk/strings.xml b/packages/SoundPicker/res/values-sk/strings.xml
index 8ff6d12..8f54350 100644
--- a/packages/SoundPicker/res/values-sk/strings.xml
+++ b/packages/SoundPicker/res/values-sk/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nepodarilo sa pridať vlastný tón zvonenia"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nepodarilo sa odstrániť vlastný tón zvonenia"</string>
<string name="app_label" msgid="3091611356093417332">"Zvuky"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Zoznam je prázdny"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Zvuk"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibrácie"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-sl/strings.xml b/packages/SoundPicker/res/values-sl/strings.xml
index 77a2a2c..1a818b2 100644
--- a/packages/SoundPicker/res/values-sl/strings.xml
+++ b/packages/SoundPicker/res/values-sl/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Tona zvonjenja po meri ni mogoče dodati"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Tona zvonjenja po meri ni mogoče izbrisati"</string>
<string name="app_label" msgid="3091611356093417332">"Zvoki"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Seznam je prazen"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Zvok"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibriranje"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-sq/strings.xml b/packages/SoundPicker/res/values-sq/strings.xml
index e35dd71..4c497bb 100644
--- a/packages/SoundPicker/res/values-sq/strings.xml
+++ b/packages/SoundPicker/res/values-sq/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Nuk mund të shtojë ton zileje të personalizuar"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Nuk mund të fshijë ton zileje të personalizuar"</string>
<string name="app_label" msgid="3091611356093417332">"Tingujt"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Lista është bosh"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Me tingull"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Me dridhje"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-sr/strings.xml b/packages/SoundPicker/res/values-sr/strings.xml
index bc573f5..2ec1f17 100644
--- a/packages/SoundPicker/res/values-sr/strings.xml
+++ b/packages/SoundPicker/res/values-sr/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Додавање прилагођене мелодије звона није успело"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Брисање прилагођене мелодије звона није успело"</string>
<string name="app_label" msgid="3091611356093417332">"Звукови"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Листа је празна"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Звук"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Вибрирање"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-sv/strings.xml b/packages/SoundPicker/res/values-sv/strings.xml
index c1dd1c2..cb1cd3a 100644
--- a/packages/SoundPicker/res/values-sv/strings.xml
+++ b/packages/SoundPicker/res/values-sv/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Det gick inte att lägga till en egen ringsignal"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Det gick inte att radera den egna ringsignalen"</string>
<string name="app_label" msgid="3091611356093417332">"Ljud"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Listan är tom"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Ljud"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Vibration"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-sw/strings.xml b/packages/SoundPicker/res/values-sw/strings.xml
index b023450..8fd6d58 100644
--- a/packages/SoundPicker/res/values-sw/strings.xml
+++ b/packages/SoundPicker/res/values-sw/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Imeshindwa kuongeza mlio maalum wa simu"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Imeshindwa kufuta mlio maalum wa simu"</string>
<string name="app_label" msgid="3091611356093417332">"Sauti"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Orodha hii haina chochote"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Sauti"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Mtetemo"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ta/strings.xml b/packages/SoundPicker/res/values-ta/strings.xml
index 38e45b7..692e58a 100644
--- a/packages/SoundPicker/res/values-ta/strings.xml
+++ b/packages/SoundPicker/res/values-ta/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"பிரத்தியேக ரிங்டோனைச் சேர்க்க முடியவில்லை"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"பிரத்தியேக ரிங்டோனை நீக்க முடியவில்லை"</string>
<string name="app_label" msgid="3091611356093417332">"ஒலிகள்"</string>
+ <string name="empty_list" msgid="2871978423955821191">"பட்டியல் காலியாக உள்ளது"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"ஒலி"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"அதிர்வு"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-te/strings.xml b/packages/SoundPicker/res/values-te/strings.xml
index 2d03ac0..ce13e53 100644
--- a/packages/SoundPicker/res/values-te/strings.xml
+++ b/packages/SoundPicker/res/values-te/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"అనుకూల రింగ్టోన్ను జోడించలేకపోయింది"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"అనుకూల రింగ్టోన్ను తొలగించలేకపోయింది"</string>
<string name="app_label" msgid="3091611356093417332">"ధ్వనులు"</string>
+ <string name="empty_list" msgid="2871978423955821191">"మీ లిస్ట్ ఖాళీగా ఉంది"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"సౌండ్"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"వైబ్రేషన్"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-th/strings.xml b/packages/SoundPicker/res/values-th/strings.xml
index cc2e43f..d5dc9b7 100644
--- a/packages/SoundPicker/res/values-th/strings.xml
+++ b/packages/SoundPicker/res/values-th/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"ไม่สามารถเพิ่มเสียงเรียกเข้าที่กำหนดเอง"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"ไม่สามารถลบเสียงเรียกเข้าที่กำหนดเอง"</string>
<string name="app_label" msgid="3091611356093417332">"เสียง"</string>
+ <string name="empty_list" msgid="2871978423955821191">"รายการว่างเปล่า"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"เสียง"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"การสั่น"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-tl/strings.xml b/packages/SoundPicker/res/values-tl/strings.xml
index c0c1712..4e3bf7e 100644
--- a/packages/SoundPicker/res/values-tl/strings.xml
+++ b/packages/SoundPicker/res/values-tl/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Hindi maidagdag ang custom na ringtone"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Hindi ma-delete ang custom na ringtone"</string>
<string name="app_label" msgid="3091611356093417332">"Mga Tunog"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Walang laman ang listahan"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Tunog"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Pag-vibrate"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-tr/strings.xml b/packages/SoundPicker/res/values-tr/strings.xml
index 955c23f..51ac541 100644
--- a/packages/SoundPicker/res/values-tr/strings.xml
+++ b/packages/SoundPicker/res/values-tr/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Özel zil sesi eklenemiyor"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Özel zil sesi silinemiyor"</string>
<string name="app_label" msgid="3091611356093417332">"Sesler"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Liste boş"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Ses"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Titreşim"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-uk/strings.xml b/packages/SoundPicker/res/values-uk/strings.xml
index 42dbfb0..a905b95 100644
--- a/packages/SoundPicker/res/values-uk/strings.xml
+++ b/packages/SoundPicker/res/values-uk/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Не вдалося додати користувацький сигнал дзвінка"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Не вдалося видалити користувацький сигнал дзвінка"</string>
<string name="app_label" msgid="3091611356093417332">"Звуки"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Список пустий"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Звук"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Вібрація"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-ur/strings.xml b/packages/SoundPicker/res/values-ur/strings.xml
index 58141d6..9cae118 100644
--- a/packages/SoundPicker/res/values-ur/strings.xml
+++ b/packages/SoundPicker/res/values-ur/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"حسب ضرورت رنگ ٹون شامل کرنے سے قاصر ہے"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"حسب ضرورت رنگ ٹون حذف کرنے سے قاصر ہے"</string>
<string name="app_label" msgid="3091611356093417332">"آوازیں"</string>
+ <string name="empty_list" msgid="2871978423955821191">"فہرست خالی ہے"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"آواز"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"وائبریشن"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-uz/strings.xml b/packages/SoundPicker/res/values-uz/strings.xml
index c39db5f..e6231f2 100644
--- a/packages/SoundPicker/res/values-uz/strings.xml
+++ b/packages/SoundPicker/res/values-uz/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Maxsus rington qo‘shib bo‘lmadi"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Maxsus ringtonni o‘chirib bo‘lmadi"</string>
<string name="app_label" msgid="3091611356093417332">"Tovushlar"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Roʻyxat boʻsh"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Tovush"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Tebranish"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-vi/strings.xml b/packages/SoundPicker/res/values-vi/strings.xml
index bed0e96..070ac16 100644
--- a/packages/SoundPicker/res/values-vi/strings.xml
+++ b/packages/SoundPicker/res/values-vi/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Không thể thêm nhạc chuông tùy chỉnh"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Không thể xóa nhạc chuông tùy chỉnh"</string>
<string name="app_label" msgid="3091611356093417332">"Âm thanh"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Danh sách này đang trống"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Âm thanh"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Rung"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-zh-rCN/strings.xml b/packages/SoundPicker/res/values-zh-rCN/strings.xml
index 864aaae..0420fc9 100644
--- a/packages/SoundPicker/res/values-zh-rCN/strings.xml
+++ b/packages/SoundPicker/res/values-zh-rCN/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"无法添加自定义铃声"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"无法删除自定义铃声"</string>
<string name="app_label" msgid="3091611356093417332">"声音"</string>
+ <string name="empty_list" msgid="2871978423955821191">"列表为空"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"声音"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"振动"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-zh-rHK/strings.xml b/packages/SoundPicker/res/values-zh-rHK/strings.xml
index 4cde32d..60d9a52 100644
--- a/packages/SoundPicker/res/values-zh-rHK/strings.xml
+++ b/packages/SoundPicker/res/values-zh-rHK/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"無法加入自訂鈴聲"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"無法刪除自訂鈴聲"</string>
<string name="app_label" msgid="3091611356093417332">"音效"</string>
+ <string name="empty_list" msgid="2871978423955821191">"清單中沒有內容"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"音效"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"震動"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-zh-rTW/strings.xml b/packages/SoundPicker/res/values-zh-rTW/strings.xml
index df8a66a..c173c0a 100644
--- a/packages/SoundPicker/res/values-zh-rTW/strings.xml
+++ b/packages/SoundPicker/res/values-zh-rTW/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"無法新增自訂鈴聲"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"無法刪除自訂鈴聲"</string>
<string name="app_label" msgid="3091611356093417332">"音效"</string>
+ <string name="empty_list" msgid="2871978423955821191">"清單中沒有任何項目"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"音效"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"震動"</string>
</resources>
diff --git a/packages/SoundPicker/res/values-zu/strings.xml b/packages/SoundPicker/res/values-zu/strings.xml
index 29a8ffe..978e925 100644
--- a/packages/SoundPicker/res/values-zu/strings.xml
+++ b/packages/SoundPicker/res/values-zu/strings.xml
@@ -26,4 +26,7 @@
<string name="unable_to_add_ringtone" msgid="4583511263449467326">"Ayikwazi ukwengeza ithoni yokukhala yangokwezifiso"</string>
<string name="unable_to_delete_ringtone" msgid="6792301380142859496">"Ayikwazi ukususa ithoni yokukhala yangokwezifiso"</string>
<string name="app_label" msgid="3091611356093417332">"Imisindo"</string>
+ <string name="empty_list" msgid="2871978423955821191">"Uhlu alunalutho"</string>
+ <string name="sound_page_title" msgid="2143312098775103522">"Umsindo"</string>
+ <string name="vibration_page_title" msgid="6519501440349124677">"Ukudlidliza"</string>
</resources>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 73fb0f0..7be6043 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -123,6 +123,7 @@
],
static_libs: [
"SystemUISharedLib",
+ "SystemUICustomizationLib",
"SettingsLib",
"androidx.leanback_leanback",
"androidx.slice_slice-core",
@@ -272,7 +273,6 @@
"tests/src/com/android/systemui/dock/DockManagerFake.java",
"tests/src/com/android/systemui/dump/LogBufferHelper.kt",
"tests/src/com/android/systemui/statusbar/phone/FakeKeyguardStateController.java",
- "tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.kt",
/* Biometric converted tests */
"tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2913c16..4fd4723 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -865,7 +865,7 @@
<activity
android:name=".settings.brightness.BrightnessDialog"
android:label="@string/quick_settings_brightness_dialog_title"
- android:theme="@style/Theme.SystemUI.QuickSettings.BrightnessDialog"
+ android:theme="@style/BrightnessDialog"
android:finishOnCloseSystemDialogs="true"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 240bace..d83596e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -99,7 +99,10 @@
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(60.dp),
modifier =
- modifier.background(MaterialTheme.colorScheme.surface).fillMaxSize().padding(32.dp)
+ modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.surface)
+ .padding(start = 32.dp, top = 92.dp, end = 32.dp, bottom = 32.dp)
) {
Crossfade(
targetState = message,
diff --git a/packages/SystemUI/compose/testing/Android.bp b/packages/SystemUI/compose/testing/Android.bp
deleted file mode 100644
index 555f42e..0000000
--- a/packages/SystemUI/compose/testing/Android.bp
+++ /dev/null
@@ -1,43 +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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
-}
-
-android_library {
- name: "SystemUIComposeTesting",
- manifest: "AndroidManifest.xml",
-
- srcs: [
- "src/**/*.kt",
- ],
-
- static_libs: [
- "PlatformComposeCore",
- "SystemUIScreenshotLib",
-
- "androidx.compose.runtime_runtime",
- "androidx.compose.material3_material3",
- "androidx.compose.ui_ui-test-junit4",
- "androidx.compose.ui_ui-test-manifest",
- ],
-
- kotlincflags: ["-Xjvm-default=all"],
-}
diff --git a/packages/SystemUI/compose/testing/AndroidManifest.xml b/packages/SystemUI/compose/testing/AndroidManifest.xml
deleted file mode 100644
index b1f7c3b..0000000
--- a/packages/SystemUI/compose/testing/AndroidManifest.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.android.systemui.testing.compose">
- <application
- android:appComponentFactory="androidx.core.app.AppComponentFactory"
- tools:replace="android:appComponentFactory">
- </application>
-</manifest>
diff --git a/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt b/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt
deleted file mode 100644
index cb9e53c..0000000
--- a/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt
+++ /dev/null
@@ -1,95 +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.testing.compose
-
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Surface
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.platform.ViewRootForTest
-import androidx.compose.ui.test.junit4.createAndroidComposeRule
-import androidx.compose.ui.test.onRoot
-import com.android.compose.theme.PlatformTheme
-import com.android.systemui.testing.screenshot.ScreenshotActivity
-import com.android.systemui.testing.screenshot.SystemUIGoldenImagePathManager
-import com.android.systemui.testing.screenshot.UnitTestBitmapMatcher
-import com.android.systemui.testing.screenshot.drawIntoBitmap
-import org.junit.rules.RuleChain
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-import platform.test.screenshot.DeviceEmulationRule
-import platform.test.screenshot.DeviceEmulationSpec
-import platform.test.screenshot.MaterialYouColorsRule
-import platform.test.screenshot.ScreenshotTestRule
-import platform.test.screenshot.getEmulatedDevicePathConfig
-
-/** A rule for Compose screenshot diff tests. */
-class ComposeScreenshotTestRule(
- emulationSpec: DeviceEmulationSpec,
- assetPathRelativeToBuildRoot: String
-) : TestRule {
- private val colorsRule = MaterialYouColorsRule()
- private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
- private val screenshotRule =
- ScreenshotTestRule(
- SystemUIGoldenImagePathManager(
- getEmulatedDevicePathConfig(emulationSpec),
- assetPathRelativeToBuildRoot
- )
- )
- private val composeRule = createAndroidComposeRule<ScreenshotActivity>()
- private val delegateRule =
- RuleChain.outerRule(colorsRule)
- .around(deviceEmulationRule)
- .around(screenshotRule)
- .around(composeRule)
- private val matcher = UnitTestBitmapMatcher
-
- override fun apply(base: Statement, description: Description): Statement {
- return delegateRule.apply(base, description)
- }
-
- /**
- * Compare [content] with the golden image identified by [goldenIdentifier] in the context of
- * [testSpec].
- */
- fun screenshotTest(
- goldenIdentifier: String,
- content: @Composable () -> Unit,
- ) {
- // Make sure that the activity draws full screen and fits the whole display instead of the
- // system bars.
- val activity = composeRule.activity
- activity.mainExecutor.execute { activity.window.setDecorFitsSystemWindows(false) }
-
- // Set the content using the AndroidComposeRule to make sure that the Activity is set up
- // correctly.
- composeRule.setContent {
- PlatformTheme {
- Surface(
- color = MaterialTheme.colorScheme.background,
- ) {
- content()
- }
- }
- }
- composeRule.waitForIdle()
-
- val view = (composeRule.onRoot().fetchSemanticsNode().root as ViewRootForTest).view
- screenshotRule.assertBitmapAgainstGolden(view.drawIntoBitmap(), goldenIdentifier, matcher)
- }
-}
diff --git a/packages/SystemUI/customization/res/values-h800dp/dimens.xml b/packages/SystemUI/customization/res/values-h800dp/dimens.xml
index 60afc8a..cb49945 100644
--- a/packages/SystemUI/customization/res/values-h800dp/dimens.xml
+++ b/packages/SystemUI/customization/res/values-h800dp/dimens.xml
@@ -17,4 +17,7 @@
<resources>
<!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
<dimen name="large_clock_text_size">200dp</dimen>
+
+ <!-- With the large clock, move up slightly from the center -->
+ <dimen name="keyguard_large_clock_top_margin">-112dp</dimen>
</resources>
diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml
index ba8f284..8eb8132 100644
--- a/packages/SystemUI/customization/res/values/dimens.xml
+++ b/packages/SystemUI/customization/res/values/dimens.xml
@@ -24,4 +24,12 @@
<item name="keyguard_clock_line_spacing_scale" type="dimen" format="float">.7</item>
<!-- Burmese line spacing multiplier between hours and minutes of the keyguard clock -->
<item name="keyguard_clock_line_spacing_scale_burmese" type="dimen" format="float">1</item>
+
+ <!-- With the large clock, move up slightly from the center -->
+ <dimen name="keyguard_large_clock_top_margin">-60dp</dimen>
+
+ <!-- additional offset for clock switch area items -->
+ <dimen name="small_clock_height">114dp</dimen>
+ <dimen name="small_clock_padding_top">28dp</dimen>
+ <dimen name="clock_padding_start">28dp</dimen>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_lock_locked.xml b/packages/SystemUI/res-keyguard/drawable/ic_lock_locked.xml
new file mode 100644
index 0000000..e572985
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_lock_locked.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M17,8H18C19.1,8 20,8.9 20,10V20C20,21.1 19.1,22 18,22H6C4.9,22 4,21.1 4,20V10C4,8.9 4.9,8 6,8H7V6C7,3.24 9.24,1 12,1C14.76,1 17,3.24 17,6V8ZM12,3C10.34,3 9,4.34 9,6V8H15V6C15,4.34 13.66,3 12,3ZM6,20V10H18V20H6ZM14,15C14,16.1 13.1,17 12,17C10.9,17 10,16.1 10,15C10,13.9 10.9,13 12,13C13.1,13 14,13.9 14,15Z"
+ android:fillColor="#5F6368"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
index c85449d0..8f1323d 100644
--- a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
@@ -30,12 +30,13 @@
<FrameLayout
android:id="@+id/inout_container"
- android:layout_height="17dp"
+ android:layout_height="@dimen/status_bar_mobile_inout_container_size"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical">
<ImageView
android:id="@+id/mobile_in"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
@@ -43,7 +44,8 @@
/>
<ImageView
android:id="@+id/mobile_out"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
android:paddingEnd="2dp"
@@ -52,11 +54,12 @@
</FrameLayout>
<ImageView
android:id="@+id/mobile_type"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
- android:paddingStart="2.5dp"
- android:paddingEnd="1dp"
+ android:adjustViewBounds="true"
+ android:paddingStart="2.5sp"
+ android:paddingEnd="1sp"
android:visibility="gone" />
<Space
android:id="@+id/mobile_roaming_space"
@@ -70,14 +73,14 @@
android:layout_gravity="center_vertical">
<com.android.systemui.statusbar.AnimatedImageView
android:id="@+id/mobile_signal"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
+ android:layout_width="@dimen/status_bar_mobile_signal_size"
systemui:hasOverlappingRendering="false"
/>
<ImageView
android:id="@+id/mobile_roaming"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_width="@dimen/status_bar_mobile_signal_size"
+ android:layout_height="@dimen/status_bar_mobile_signal_size"
android:layout_gravity="top|start"
android:src="@drawable/stat_sys_roaming"
android:contentDescription="@string/data_connection_roaming"
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index c394fb6..366ee57 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -113,7 +113,7 @@
<string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"Pincode is vereist na opnieuw opstarten apparaat"</string>
<string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"Wachtwoord is vereist na opnieuw opstarten apparaat"</string>
<string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik in plaats daarvan het patroon voor extra beveiliging"</string>
- <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik in plaats daarvan de pincode voor extra beveiliging"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik de pincode voor extra beveiliging"</string>
<string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik in plaats daarvan het wachtwoord voor extra beveiliging"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Apparaat vergrendeld door beheerder"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Apparaat is handmatig vergrendeld"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index a147d07..546f31b 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -81,7 +81,7 @@
<string name="kg_prompt_password_auth_timeout" msgid="5809110458491920871">"Потрібен додатковий захист. Пароль довго не використовувався."</string>
<string name="kg_prompt_pattern_auth_timeout" msgid="1860605401869262178">"Потрібен додатковий захист. Ключ довго не використовувався."</string>
<string name="kg_prompt_auth_timeout" msgid="6620679830980315048">"Потрібен додатковий захист. Пристрій довго не розблоковувався."</string>
- <string name="kg_face_locked_out" msgid="2751559491287575">"Не розблоковано (фейсконтроль). Забагато спроб."</string>
+ <string name="kg_face_locked_out" msgid="2751559491287575">"Не розблоковано (фейс-контроль). Забагато спроб."</string>
<string name="kg_fp_locked_out" msgid="6228277682396768830">"Не розблоковано (відбиток пальця). Забагато спроб."</string>
<string name="kg_trust_agent_disabled" msgid="5400691179958727891">"Довірчий агент недоступний"</string>
<string name="kg_primary_auth_locked_out_pin" msgid="5492230176361601475">"Неправильний PIN-код введено забагато разів"</string>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 39dd90e..8c81733 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -95,9 +95,6 @@
<dimen name="num_pad_key_margin_end">12dp</dimen>
<!-- additional offset for clock switch area items -->
- <dimen name="small_clock_height">114dp</dimen>
- <dimen name="small_clock_padding_top">28dp</dimen>
- <dimen name="clock_padding_start">28dp</dimen>
<dimen name="below_clock_padding_start">32dp</dimen>
<dimen name="below_clock_padding_end">16dp</dimen>
<dimen name="below_clock_padding_start_icons">28dp</dimen>
diff --git a/packages/SystemUI/res-product/values-af/strings.xml b/packages/SystemUI/res-product/values-af/strings.xml
index 1fab1d4..c1a6803 100644
--- a/packages/SystemUI/res-product/values-af/strings.xml
+++ b/packages/SystemUI/res-product/values-af/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Die werkprofiel sal verwyder word, wat alle profieldata sal uitvee."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou tablet te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd geteken. Na nóg <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal jy gevra word om jou e-posrekening te gebruik om jou foon te ontsluit.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Foon het afgeskakel weens hitte"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Toestel het afgeskakel weens hitte"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet het afgeskakel weens hitte"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Jou foon werk nou normaal.\nTik vir meer inligting"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Jou toestel werk nou normaal.\nTik vir meer inligting"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Jou tablet werk nou normaal.\nTik vir meer inligting"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Jou foon was te warm en het afgeskakel om af te koel. Jou foon werk nou normaal.\n\nJou foon sal dalk te warm word as jy:\n • Hulpbronintensiewe apps (soos dobbel-, video- of navigasieapps) gebruik\n • Groot lêers af- of oplaai\n • Jou foon in hoë temperature gebruik"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Jou toestel was te warm en het afgeskakel om af te koel. Jou toestel werk nou normaal.\n\nJou toestel sal dalk te warm word as jy:\n • Hulpbronintensiewe apps (soos dobbel-, video- of navigasieapps) gebruik\n • Groot lêers af- of oplaai\n • Jou toestel in hoë temperature gebruik"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Jou tablet was te warm en het afgeskakel om af te koel. Jou tablet werk nou normaal.\n\nJou tablet sal dalk te warm word as jy:\n • Hulpbronintensiewe apps (soos dobbel-, video- of navigasieapps) gebruik\n • Groot lêers af- of oplaai\n • Jou tablet in hoë temperature gebruik"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Foon word warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Toestel word warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet word warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Sommige kenmerke word beperk terwyl die foon besig is om af te koel.\nTik vir meer inligting"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Sommige kenmerke word beperk terwyl die toestel besig is om af te koel.\nTik vir meer inligting"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Sommige kenmerke word beperk terwyl die tablet besig is om af te koel.\nTik vir meer inligting"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Jou foon sal outomaties probeer afkoel. Jy kan steeds jou foon gebruik, maar dit sal dalk stadiger werk.\n\nJou foon sal normaal werk nadat dit afgekoel het."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Jou toestel sal outomaties probeer afkoel. Jy kan steeds jou toestel gebruik, maar dit sal dalk stadiger werk.\n\nJou toestel sal normaal werk nadat dit afgekoel het."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Jou tablet sal outomaties probeer afkoel. Jy kan steeds jou tablet gebruik, maar dit sal dalk stadiger werk.\n\nJou tablet sal normaal werk nadat dit afgekoel het."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Die vingerafdruksensor is op die aan/af-skakelaar. Dit is die plat knoppie langs die verhewe volumeknoppie aan die kant van die tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Die vingerafdruksensor is op die aan/af-skakelaar. Dit is die plat knoppie langs die verhewe volumeknoppie aan die kant van die toestel."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Die vingerafdruksensor is op die aan/af-skakelaar. Dit is die plat knoppie langs die verhewe volumeknoppie aan die kant van die foon."</string>
diff --git a/packages/SystemUI/res-product/values-am/strings.xml b/packages/SystemUI/res-product/values-am/strings.xml
index ab55d22..b8b2df8 100644
--- a/packages/SystemUI/res-product/values-am/strings.xml
+++ b/packages/SystemUI/res-product/values-am/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለመክፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ስልክ በሙቀት ምክንያት ጠፍቷል"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"መሣሪያ በሙቀት ምክንያት ጠፍቷል"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ጡባዊ በሙቀት ምክንያት ጠፍቷል"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"የእርስዎ ስልክ በመደበኛነት በማሄድ ላይ ነው።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"የእርስዎ ጡባዊ በመደበኛነት በማሄድ ላይ ነው።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"የእርስዎ ጡባዊ በመደበኛነት በማሄድ ላይ ነው።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"የእርስዎ ስልክ በጣም ግሎ ነበር ስለዚህ እንዲቀዘቅዝ ጠፍቷል። የእርስዎ ስልክ አሁን በመደበኛነት በማሄድ ላይ ነው።\n\nየሚከተሉትን ካደረጉ የእርስዎ ስልክ በጣም ሊግል ይችላል፦\n • ኃይል በጣም የሚጠቀሙ መተግበሪያዎችን (እንደ ጨዋታ፣ ቪድዮ ወይም የአሰሳ መተግበሪያዎች ያሉ) ከተጠቀሙ\n • ትልልቅ ፋይሎችን ካወረዱ ወይም ከሰቀሉ\n • ስልክዎን በከፍተኛ ሙቀት ውስጥ ከተጠቀሙ"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"የእርስዎ መሣሪያ በጣም ግሎ ነበር ስለዚህ እንዲቀዘቅዝ ጠፍቷል። የእርስዎ መሣሪያ አሁን በመደበኛነት በማሄድ ላይ ነው።\n\nየሚከተሉትን ካደረጉ የእርስዎ መሣሪያ በጣም ሊግል ይችላል፦\n • ኃይል በጣም የሚጠቀሙ መተግበሪያዎችን (እንደ ጨዋታ፣ ቪድዮ ወይም የአሰሳ መተግበሪያዎች ያሉ) ከተጠቀሙ\n • ትልልቅ ፋይሎችን ካወረዱ ወይም ከሰቀሉ\n • መሣሪያዎን በከፍተኛ ሙቀት ውስጥ ከተጠቀሙ"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"የእርስዎ ጡባዊ በጣም ግሎ ነበር ስለዚህ እንዲቀዘቅዝ ጠፍቷል። የእርስዎ ጡባዊ አሁን በመደበኛነት በማሄድ ላይ ነው።\n\nየሚከተሉትን ካደረጉ የእርስዎ ጡባዊ በጣም ሊግል ይችላል፦\n • ኃይል በጣም የሚጠቀሙ መተግበሪያዎችን (እንደ ጨዋታ፣ ቪድዮ ወይም የአሰሳ መተግበሪያዎች ያሉ) ከተጠቀሙ\n • ትልልቅ ፋይሎችን ካወረዱ ወይም ከሰቀሉ\n • ጡባዊዎን በከፍተኛ ሙቀት ውስጥ ከተጠቀሙ"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"የስልክ ሙቀት እየጨመረ ነው"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"የመሣሪያ ሙቀት እየጨመረ ነው"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"የጡባዊ ሙቀት እየጨመረ ነው"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ስልክ እየቀዘቀዘ ሳለ አንዳንድ ባህሪያት ይገደባሉ።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"መሣሪያ እየቀዘቀዘ ሳለ አንዳንድ ባህሪያት ይገደባሉ።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ጡባዊ እየቀዘቀዘ ሳለ አንዳንድ ባህሪያት ይገደባሉ።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"የእርስዎ ስልክ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ስልክዎን መጠቀም ይችላሉ ነገር ግን ቀትፋፋ ሆኖ ሊያሄድ ይችላል።\n\nአንዴ ስልክዎ ከቀዘቀዘ በኋላ በመደበኛነት ያሄዳል።"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"መሣሪያዎ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም መሣሪያዎን መጠቀም ይችላሉ ነገር ግን ቀርፋፋ ሆኖ ሊያሄድ ይችላል።\n\nአንዴ መሣሪያዎ ከቀዘቀዘ በኋላ በመደበኛነት ያሄዳል"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"ጡባዊዎ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ጡባዊዎን መጠቀም ይችላሉ ነገር ግን ቀርፋፋ ሆኖ ሊያሄድ ይችላል።\n\nአንዴ ጡባዊዎ ከቀዘቀዘ በኋላ በመደበኛነት ያሄዳል።"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"የጣት አሻራ ዳሳሹ የማብሪያ/ማጥፊያ ቁልፉ ላይ ነው። በጡባዊው ጫፍ ላይ ከፍ ካለው የድምፅ አዝራር ቀጥሎ ያለው ጠፍጣፋ አዝራር ነው።"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"የጣት አሻራ ዳሳሹ የማብሪያ/ማጥፊያ ቁልፉ ላይ ነው። በመሣሪያው ጫፍ ላይ ከፍ ካለው የድምፅ አዝራር ቀጥሎ ያለው ጠፍጣፋ አዝራር ነው።"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"የጣት አሻራ ዳሳሹ የማብሪያ/ማጥፊያ ቁልፉ ላይ ነው። በስልኩ ጫፍ ላይ ከፍ ካለው የድምፅ አዝራር ቀጥሎ ያለው ጠፍጣፋ አዝራር ነው።"</string>
diff --git a/packages/SystemUI/res-product/values-ar/strings.xml b/packages/SystemUI/res-product/values-ar/strings.xml
index 1664d6f..4d4d8d0 100644
--- a/packages/SystemUI/res-product/values-ar/strings.xml
+++ b/packages/SystemUI/res-product/values-ar/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"أخطأت في محاولة فتح قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> مرة. ستتم إزالة الملف الشخصي للعمل، ومن ثم يتم حذف جميع بياناته."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستُطالَب بفتح قفل الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n يُرجى إعادة المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> محاولة غير ناجحة أخرى، ستُطالَب بفتح قفل الهاتف باستخدام حساب بريد إلكتروني.\n\n يُرجى إعادة المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"تم إطفاء الهاتف بسبب ارتفاع درجة حرارته"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"تم إطفاء الجهاز بسبب ارتفاع درجة حرارته"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"تم إطفاء الجهاز اللوحي لارتفاع حرارته"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"يعمل هاتفك الآن بشكل طبيعي.\nانقر للحصول على مزيد من المعلومات."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"يعمل جهازك الآن بشكل طبيعي.\nانقر للحصول على مزيد من المعلومات."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"يعمل جهازك اللوحي الآن بشكل طبيعي.\nانقر للحصول على مزيد من المعلومات."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ارتفعت درجة حرارة هاتفك بشدة، لذا تم إطفاؤه لخفض درجة حرارته. يعمل هاتفك الآن بشكل طبيعي.\n\nقد ترتفع درجة حرارة هاتفك بشدة إذا:\n • استخدمت تطبيقات تستهلك موارد الجهاز بصورة كبيرة (مثل تطبيقات الألعاب أو الفيديو أو التنقل)\n • نزَّلت أو حمَّلت ملفات كبيرة الحجم\n • استخدمت هاتفك وسط أجواء مرتفعة الحرارة"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ارتفعت درجة حرارة جهازك بشدة، لذا تم إطفاؤه لخفض درجة حرارته. يعمل جهازك الآن بشكل طبيعي.\n\nقد ترتفع درجة حرارة جهازك بشدة إذا:\n • استخدمت تطبيقات تستهلك موارد الجهاز بصورة كبيرة (مثل تطبيقات الألعاب أو الفيديو أو التنقل)\n • نزَّلت أو حمَّلت ملفات كبيرة الحجم\n • استخدمت جهازك وسط أجواء مرتفعة الحرارة"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ارتفعت درجة حرارة جهازك اللوحي بشدة، لذا تم إطفاؤه لخفض درجة حرارته. يعمل جهازك اللوحي الآن بشكل طبيعي.\n\nقد ترتفع درجة حرارة جهازك اللوحي بشدة إذا:\n • استخدمت تطبيقات تستهلك موارد الجهاز بصورة كبيرة (مثل تطبيقات الألعاب أو الفيديو أو التنقل)\n • نزَّلت أو حمَّلت ملفات كبيرة الحجم\n • استخدمت جهازك اللوحي وسط أجواء مرتفعة الحرارة"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"تزداد درجة حرارة الهاتف"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"تزداد درجة حرارة الجهاز"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"تزداد درجة حرارة الجهاز اللوحي"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"سيتم فرض قيود على بعض الميزات إلى أن تنخفض درجة حرارة الهاتف.\nانقر للحصول على مزيد من المعلومات."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"سيتم فرض قيود على بعض الميزات إلى أن تنخفض درجة حرارة الجهاز.\nانقر للحصول على مزيد من المعلومات."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"سيتم فرض قيود على بعض الميزات إلى أن تنخفض درجة حرارة الجهاز اللوحي.\nانقر للحصول على مزيد من المعلومات."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"سيحاول الهاتف تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام هاتفك، ولكنه قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الهاتف، سيستعيد سرعته المعتادة."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"سيحاول جهازك تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام جهازك، ولكنه قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الجهاز، سيستعيد سرعته المعتادة."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"سيحاول جهازك اللوحي تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام جهازك اللوحي، ولكنه قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الجهاز اللوحي، سيستعيد سرعته المعتادة."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"توجد أداة استشعار بصمة الإصبع على زر التشغيل. زر التشغيل هو الزر المسطّح بجانب زرَّي التحكّم بمستوى الصوت البارزَين في الجزء الجانبي من الجهاز اللوحي."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"توجد أداة استشعار بصمة الإصبع على زر التشغيل. زر التشغيل هو الزر المسطّح بجانب زرَّي التحكّم بمستوى الصوت البارزَين في الجزء الجانبي من الجهاز."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"توجد أداة استشعار بصمة الإصبع على زر التشغيل. زر التشغيل هو الزر المسطّح بجانب زرَّي التحكّم بمستوى الصوت البارزَين في الجزء الجانبي من الهاتف."</string>
diff --git a/packages/SystemUI/res-product/values-as/strings.xml b/packages/SystemUI/res-product/values-as/strings.xml
index 05c69b8..40aab2f 100644
--- a/packages/SystemUI/res-product/values-as/strings.xml
+++ b/packages/SystemUI/res-product/values-as/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"আপুনি ফ’নটো আনলক কৰিবলৈ <xliff:g id="NUMBER">%d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰিছে। কৰ্মস্থানৰ প্ৰ’ফাইলটো আঁতৰোৱা হ’ব, যিয়ে প্ৰ’ফাইলটোৰ আটাইবোৰ ডেটা মচি পেলাব।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"আপুনি নিজৰ আনলক কৰা আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাক নিজৰ টেবলেটটো এটা ইমেইল একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ’ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পাছত পুনৰ চেষ্টা কৰক।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"আপুনি নিজৰ আনলক কৰা আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g> বাৰ ভুলকৈ আঁকিছে। আৰু <xliff:g id="NUMBER_1">%2$d</xliff:g> বাৰ ভুলকৈ প্ৰয়াস কৰাৰ পাছত আপোনাক নিজৰ ফ’নটো এটা ইমেইল একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ’ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পাছত পুনৰ চেষ্টা কৰক।"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ফ’নটো গৰম হোৱাৰ কাৰণে অফ হৈছিল"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ডিভাইচটো গৰম হোৱাৰ কাৰণে অফ হৈছিল"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"টেবলেটটো গৰম হোৱাৰ কাৰণে অফ হৈছিল"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"আপোনাৰ ফ’নটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\nঅধিক তথ্যৰ বাবে টিপক"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"আপোনাৰ ডিভাইচটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\nঅধিক তথ্যৰ বাবে টিপক"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"আপোনাৰ টেবলেটটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\nঅধিক তথ্যৰ বাবে টিপক"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"আপোনাৰ ফ’নটো অত্যধিক গৰম হোৱাৰ বাবে সেইটো ঠাণ্ডা কৰিবলৈ অফ হৈছিল। আপোনাৰ ফ’নটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\n\nআপোনাৰ ফ’নটো গৰম হ’ব পাৰে, যদিহে আপুনি:\n • ফ’নটোৰ হাৰ্ডৱেৰ অত্যধিক মাত্ৰাত ব্যৱহাৰ কৰা এপ্ (যেনে- ভিডিঅ’ গে’ম, ভিডিঅ’, দিক্-নিৰ্দেশনাৰ এপ্) ব্যৱহাৰ কৰে\n • ডাঙৰ আকাৰৰ ফাইল আপল’ড অথবা ডাউনল’ড কৰে\n • আপোনাৰ ফ’নটো উচ্চ তাপমাত্ৰাৰ পৰিৱেশত ব্যৱহাৰ কৰে"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"আপোনাৰ ডিভাইচটো অত্যধিক গৰম হোৱাৰ বাবে সেইটো ঠাণ্ডা কৰিবলৈ অফ হৈছিল। আপোনাৰ ডিভাইচটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\n\nআপোনাৰ ডিভাইচটো গৰম হ’ব পাৰে, যদিহে আপুনি:\n • ডিভাইচটোৰ হাৰ্ডৱেৰ অত্যধিক মাত্ৰাত ব্যৱহাৰ কৰা এপ্ (যেনে- ভিডিঅ’ গে’ম, ভিডিঅ’, দিক্-নিৰ্দেশনাৰ এপ্) ব্যৱহাৰ কৰে\n • ডাঙৰ আকাৰৰ ফাইল আপল’ড অথবা ডাউনল’ড কৰে\n • আপোনাৰ ডিভাইচটো উচ্চ তাপমাত্ৰাৰ পৰিৱেশত ব্যৱহাৰ কৰে"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"আপোনাৰ টেবলেটটো অত্যধিক গৰম হোৱাৰ বাবে সেইটো ঠাণ্ডা কৰিবলৈ অফ হৈছিল। আপোনাৰ টেবলেটটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\n\nআপোনাৰ টেবলেটটো গৰম হ’ব পাৰে, যদিহে আপুনি:\n • টেবলেটটোৰ হাৰ্ডৱেৰ অত্যধিক মাত্ৰাত ব্যৱহাৰ কৰা এপ্ (যেনে- ভিডিঅ’ গে’ম, ভিডিঅ’, দিক্-নিৰ্দেশনাৰ এপ্) ব্যৱহাৰ কৰে\n • ডাঙৰ আকাৰৰ ফাইল আপল’ড অথবা ডাউনল’ড কৰে\n • আপোনাৰ টেবলেটটো উচ্চ তাপমাত্ৰাৰ পৰিৱেশত ব্যৱহাৰ কৰে"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ফ’নটো গৰম হ’বলৈ ধৰিছে"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ডিভাইচটো গৰম হবলৈ ধৰিছে"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"টেবলেটটো গৰম হবলৈ ধৰিছে"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ফ’নটো ঠাণ্ডা হ’বলৈ ধৰোঁতে কিছুমান সুবিধা উপলব্ধ নহয়।\nঅধিক তথ্যৰ বাবে টিপক"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ডিভাইচটো ঠাণ্ডা হ’বলৈ ধৰোঁতে কিছুমান সুবিধা উপলব্ধ নহয়।\nঅধিক তথ্যৰ বাবে টিপক"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"টেবলেটটো ঠাণ্ডা হ’বলৈ ধৰোঁতে কিছুমান সুবিধা উপলব্ধ নহয়।\nঅধিক তথ্যৰ বাবে টিপক"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"আপোনাৰ ফ’নটোৱে নিজে নিজে ঠাণ্ডা হ’বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি ফ’নটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nফ’নটো ঠাণ্ডা হোৱাৰ পাছত ই আগৰ নিচিনাকৈ চলিব।"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"আপোনাৰ ডিভাইচটোৱে নিজে নিজে ঠাণ্ডা হ’বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি ডিভাইচটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nআপোনাৰ ডিভাইচটো ঠাণ্ডা হোৱাৰ পাছত ই আগৰ নিচিনাকৈ চলিব।"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"আপোনাৰ টেবলেটটোৱে নিজে নিজে ঠাণ্ডা হ’বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি টেবলেটটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nআপোনাৰ টেবলেটটো ঠাণ্ডা হোৱাৰ পাছত ই আগৰ নিচিনাকৈ চলিব।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো পাৱাৰ বুটামটোত আছে। এইটো হৈছে টেবলেটটোৰ প্ৰান্তত থকা উঠঙা ভলিউমৰ বুটামটোৰ কাষত থকা চেপেটা বুটামটো।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো পাৱাৰ বুটামটোত আছে। এইটো হৈছে ডিভাইচটোৰ প্ৰান্তত থকা উঠঙা ভলিউমৰ বুটামটোৰ কাষত থকা চেপেটা বুটামটো।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো পাৱাৰ বুটামটোত আছে। এইটো হৈছে ফ’নটোৰ প্ৰান্তত থকা উঠঙা ভলিউমৰ বুটামটোৰ কাষত থকা চেপেটা বুটামটো।"</string>
diff --git a/packages/SystemUI/res-product/values-az/strings.xml b/packages/SystemUI/res-product/values-az/strings.xml
index 3cc7d8c..b7e93fd 100644
--- a/packages/SystemUI/res-product/values-az/strings.xml
+++ b/packages/SystemUI/res-product/values-az/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini açmaq üçün <xliff:g id="NUMBER">%d</xliff:g> dəfə yanlış cəhd etmisiniz. İş profili silinəcək və bütün data ləğv ediləcək."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilid açma modelini <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra planşet kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilid açma modelini artıq <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra telefon kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə sonra cəhd edin."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon qızdığı üçün söndü"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Cihaz qızdığı üçün söndü"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Planşet qızdığı üçün söndü"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Hazırda telefon normal işləyir.\nƏtraflı məlumat üçün toxunun"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Hazırda cihaz normal işləyir.\nƏtraflı məlumat üçün toxunun"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Hazırda planşet normal işləyir.\nƏtraflı məlumat üçün toxunun"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon çox isti idi və soyumaq üçün söndü. Hazırda telefon normal işləyir.\n\nTelefon bu hallarda çox isinə bilər:\n • Çoxresurslu tətbiq (oyun, video və ya naviqasiya tətbiqi kimi) istifadə etsəniz\n • Böyük fayl endirsəniz və ya yükləsəniz\n • Telefonu yüksək temperaturda istifadə etsəniz"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Cihaz çox isti idi və soyumaq üçün söndü. Hazırda cihaz normal işləyir.\n\nCihaz bu hallarda çox isinə bilər:\n • Çoxresurslu tətbiq (oyun, video və ya naviqasiya tətbiqi kimi) istifadə etsəniz\n • Böyük fayl endirsəniz və ya yükləsəniz\n • Cihazı yüksək temperaturda istifadə etsəniz"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Planşet çox isti idi və soyumaq üçün söndü. Hazırda planşet normal işləyir.\n\nPlanşet bu hallarda çox isinə bilər:\n • Çoxresurslu tətbiq (oyun, video və ya naviqasiya tətbiqi kimi) istifadə etsəniz\n • Böyük fayl endirsəniz və ya yükləsəniz\n • Planşeti yüksək temperaturda istifadə etsəniz"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon isinir"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Cihaz isinir"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Planşet isinir"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Telefon soyuyarkən bəzi funksiyalar məhdudlaşdırılır.\nƏtraflı məlumat üçün toxunun"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Cihaz soyuyarkən bəzi funksiyalar məhdudlaşdırılır.\nƏtraflı məlumat üçün toxunun"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Planşet soyuyarkən bəzi funksiyalar məhdudlaşdırılır.\nƏtraflı məlumat üçün toxunun"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefon avtomatik soyuyacaq. Telefondan istifadə mümkündür, lakin asta işləyə bilər.\n\nSoyuduqdan sonra normal işləyəcək."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Cihaz avtomatik soyuyacaq. Cihazdan istifadə mümkündür, lakin asta işləyə bilər.\n\nSoyuduqdan sonra normal işləyəcək."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Planşet avtomatik soyuyacaq. Planşetdən istifadə mümkündür, lakin asta işləyə bilər.\n\nSoyuduqdan sonra normal işləyəcək."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Barmaq izi sensoru enerji düyməsinin üzərindədir. Bu, planşetin kənarındakı qabarıq səs düyməsinin yanındakı yastı düymədir."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Barmaq izi sensoru enerji düyməsinin üzərindədir. Bu, cihazın kənarındakı qabarıq səs düyməsinin yanındakı yastı düymədir."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Barmaq izi sensoru enerji düyməsinin üzərindədir. Bu, telefonun kənarındakı qabarıq səs düyməsinin yanındakı yastı düymədir."</string>
diff --git a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
index 07d8c94..067c16b 100644
--- a/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-product/values-b+sr+Latn/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Uklonićemo poslovni profil, čime se brišu svi podaci sa profila."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate tablet pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Netačno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako pogrešno pokušate još <xliff:g id="NUMBER_1">%2$d</xliff:g> puta, zatražićemo da otključate telefon pomoću imejl naloga.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon se isključio zbog toplote"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Uređaj se isključio zbog toplote"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet se isključio zbog toplote"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefon sada funkcioniše normalno.\nDodirnite za više informacija"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Uređaj sada funkcioniše normalno.\nDodirnite za više informacija"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tablet sada funkcioniše normalno.\nDodirnite za više informacija"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon je bio prevruć, pa se isključio da se ohladi. Sada radi normalno.\n\nTelefon može previše da se ugreje ako:\n • koristite aplikacije koje zahtevaju puno resursa (npr. video igre, video ili aplikacije za navigaciju)\n • preuzimate ili otpremate velike fajlove\n • koristite telefon na visokoj temperaturi"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Uređaj je bio prevruć, pa se isključio da se ohladi. Sada radi normalno.\n\nUređaj može previše da se ugreje ako:\n • koristite aplikacije koje zahtevaju puno resursa (npr. video igre, video ili aplikacije za navigaciju)\n • preuzimate ili otpremate velike fajlove\n • koristite uređaj na visokoj temperaturi"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablet je bio prevruć, pa se isključio da se ohladi. Sada radi normalno.\n\nTablet može previše da se ugreje ako:\n • koristite aplikacije koje zahtevaju puno resursa (npr. video igre, video ili aplikacije za navigaciju)\n • preuzimate ili otpremate velike fajlove\n • koristite tablet na visokoj temperaturi"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon se zagrejao"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Uređaj se zagrejao"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet se zagrejao"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Neke funkcije su ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Neke funkcije su ograničene dok se uređaj ne ohladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Neke funkcije su ograničene dok se tablet ne ohladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefon će automatski pokušati da se ohladi. I dalje možete da koristite telefon, ali će možda raditi sporije.\n\nKad se telefon ohladi, funkcionisaće normalno."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Uređaj će automatski pokušati da se ohladi. I dalje možete da koristite uređaj, ali će možda raditi sporije.\n\nKad se uređaj ohladi, funkcionisaće normalno."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablet će automatski pokušati da se ohladi. I dalje možete da koristite tablet, ali će možda raditi sporije.\n\nKad se tablet ohladi, funkcionisaće normalno."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor za otisak prsta se nalazi na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na ivici tableta."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor za otisak prsta se nalazi na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na ivici uređaja."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor za otisak prsta se nalazi na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na ivici telefona."</string>
diff --git a/packages/SystemUI/res-product/values-be/strings.xml b/packages/SystemUI/res-product/values-be/strings.xml
index e9c491a..f9ef0d5 100644
--- a/packages/SystemUI/res-product/values-be/strings.xml
+++ b/packages/SystemUI/res-product/values-be/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Вы не змаглі разблакіраваць тэлефон столькі разоў: <xliff:g id="NUMBER">%d</xliff:g>. Працоўны профіль будзе выдалены, і гэта прывядзе да выдалення ўсіх даных у профілі."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць планшэт, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Вы няправільна ўвялі ўзор разблакіроўкі столькі разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькіх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакіраваць тэлефон, увайшоўшы ва ўліковы запіс электроннай пошты.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Тэлефон выключыўся з-за перагрэву"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Прылада выключылася з-за перагрэву"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Планшэт выключыўся з-за перагрэву"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Ваш тэлефон працуе ў звычайным рэжыме.\nНацісніце, каб даведацца больш"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Ваша прылада працуе ў звычайным рэжыме.\nНацісніце, каб даведацца больш"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Ваш планшэт працуе ў звычайным рэжыме.\nНацісніце, каб даведацца больш"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Ваш тэлефон пераграваўся, таму ён выключыўся, каб астыць. Зараз тэлефон працуе ў звычайным рэжыме.\n\nТэлефон можа перагравацца пры:\n • выкарыстанні рэсурсаёмістых праграм (напрыклад, гульняў або праграм, звязаных з відэа або навігацыяй);\n • спампоўванні або запампоўванні вялікіх файлаў;\n • выкарыстанні тэлефона пры высокіх тэмпературах."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Ваша прылада перагравалася, таму яна выключылася, каб астыць. Зараз прылада працуе ў звычайным рэжыме.\n\nПрылада можа перагравацца пры:\n • выкарыстанні рэсурсаёмістых праграм (напрыклад, гульняў або праграм, звязаных з відэа або навігацыяй);\n • спампоўванні або запампоўванні вялікіх файлаў;\n • выкарыстанні прылады пры высокіх тэмпературах."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Ваш планшэт пераграваўся, таму ён выключыўся, каб астыць. Зараз планшэт працуе ў звычайным рэжыме.\n\nПланшэт можа перагравацца пры:\n • выкарыстанні рэсурсаёмістых праграм (напрыклад, гульняў або праграм, звязаных з відэа або навігацыяй);\n • спампоўванні або запампоўванні вялікіх файлаў;\n • выкарыстанні планшэта пры высокіх тэмпературах."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Тэлефон награваецца"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Прылада награваецца"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Планшэт награваецца"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Некаторыя функцыі абмежаваны, пакуль тэлефон не астыне.\nНацісніце, каб даведацца больш"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Некаторыя функцыі абмежаваны, пакуль прылада не астыне.\nНацісніце, каб даведацца больш"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Некаторыя функцыі абмежаваны, пакуль планшэт не астыне.\nНацісніце, каб даведацца больш"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Ваш тэлефон будзе астываць аўтаматычна. Вы можаце і далей ім карыстацца, але ён можа працаваць больш павольна.\n\nПасля таго як тэлефон астыне, ён будзе працаваць у звычайным рэжыме."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Ваша прылада будзе астываць аўтаматычна. Вы можаце і далей ёй карыстацца, але яна можа працаваць больш павольна.\n\nПасля таго як прылада астыне, яна будзе працаваць у звычайным рэжыме."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Ваш планшэт будзе астываць аўтаматычна. Вы можаце і далей ім карыстацца, але ён можа працаваць больш павольна.\n\nПасля таго як планшэт астыне, ён будзе працаваць у звычайным рэжыме."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сканер адбіткаў пальцаў знаходзіцца на кнопцы сілкавання. Гэта плоская кнопка побач з выпуклай кнопкай гучнасці на бакавой грані планшэта."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сканер адбіткаў пальцаў знаходзіцца на кнопцы сілкавання. Гэта плоская кнопка побач з выпуклай кнопкай гучнасці на бакавой грані прылады."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сканер адбіткаў пальцаў знаходзіцца на кнопцы сілкавання. Гэта плоская кнопка побач з выпуклай кнопкай гучнасці на бакавой грані тэлефона."</string>
diff --git a/packages/SystemUI/res-product/values-bg/strings.xml b/packages/SystemUI/res-product/values-bg/strings.xml
index 3542558..40140c4 100644
--- a/packages/SystemUI/res-product/values-bg/strings.xml
+++ b/packages/SystemUI/res-product/values-bg/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Опитахте да отключите телефона и сбъркахте <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета си посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Телефонът се изключи поради загряване"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Устройството се изключи поради загряване"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Таблетът се изключи поради загряване"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Телефонът ви вече работи нормално.\nДокоснете за още информация"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Устройството ви вече работи нормално.\nДокоснете за още информация"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Таблетът ви вече работи нормално.\nДокоснете за още информация"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Телефонът ви бе твърде горещ, затова се изключи с цел охлаждане. Вече работи нормално.\n\nТелефонът ви може да стане твърде горещ, ако:\n • използвате натоварващи приложения (като например игри или приложения за видео или за навигация);\n • изтегляте или качвате големи файлове;\n • използвате устройството си при високи температури."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Устройството ви бе твърде горещо, затова се изключи с цел охлаждане. Вече работи нормално.\n\nУстройството ви може да стане твърде горещо, ако:\n • използвате натоварващи приложения (като например игри или приложения за видео или за навигация);\n • изтегляте или качвате големи файлове;\n • използвате устройството си при високи температури."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Таблетът ви бе твърде горещ, затова се изключи с цел охлаждане. Вече работи нормално.\n\nТаблетът ви може да стане твърде горещ, ако:\n • използвате натоварващи приложения (като например игри или приложения за видео или за навигация);\n • изтегляте или качвате големи файлове;\n • използвате устройството си при високи температури."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Телефонът загрява"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Устройството загрява"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Таблетът загрява"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Някои функции са ограничени, докато телефонът се охлажда.\nДокоснете за още информация"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Някои функции са ограничени, докато устройството се охлажда.\nДокоснете за още информация"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Някои функции са ограничени, докато таблетът се охлажда.\nДокоснете за още информация"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Телефонът ви автоматично ще направи опит да се охлади. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Устройството ви автоматично ще направи опит да се охлади. Пак можете да го използвате, но то може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Таблетът ви автоматично ще направи опит да се охлади. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сензорът за отпечатъци се намира върху бутона за захранване. Този бутон е плосък и е разположен на ръба на таблета до повдигнатия бутон за силата на звука."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сензорът за отпечатъци се намира върху бутона за захранване. Този бутон е плосък и е разположен на ръба на устройството до повдигнатия бутон за силата на звука."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сензорът за отпечатъци се намира върху бутона за захранване. Този бутон е плосък и е разположен на ръба на телефона до повдигнатия бутон за силата на звука."</string>
diff --git a/packages/SystemUI/res-product/values-bn/strings.xml b/packages/SystemUI/res-product/values-bn/strings.xml
index 0984de2..19165ef 100644
--- a/packages/SystemUI/res-product/values-bn/strings.xml
+++ b/packages/SystemUI/res-product/values-bn/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল পদ্ধতিতে ফোন আনলক করার চেষ্টা করেছেন। অফিস প্রোফাইলটি সরিয়ে দেওয়া হবে, যার ফলে প্রোফাইলের সমস্ত ডেটা মুছে যাবে।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল পদ্ধতিতে প্যাটার্ন আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার এটি করলে আপনাকে প্যাটার্ন আনলক করতে একটি ইমেল অ্যাকাউন্ট ব্যবহার করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ড পরে আবার চেষ্টা করুন।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"আপনি <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল পদ্ধতিতে প্যাটার্ন আনলক করার চেষ্টা করেছেন। আরও <xliff:g id="NUMBER_1">%2$d</xliff:g> বার এটি করলে আপনাকে প্যাটার্ন আনলক করতে একটি ইমেল অ্যাকাউন্ট ব্যবহারের করতে বলা হবে।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ড পরে আবার চেষ্টা করুন।"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ফোন গরম হওয়ার জন্য বন্ধ হয়ে গেছে"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ডিভাইস গরম হওয়ার জন্য বন্ধ হয়ে গেছে"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ট্যাবলেট গরম হওয়ার জন্য বন্ধ হয়ে গেছে"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"আপনার ফোন এখন ভালভাবে কাজ করছে।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"আপনার ডিভাইস এখন ভালভাবে কাজ করছে।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"আপনার ট্যাবলেট এখন ভালভাবে কাজ করছে।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"আপনার ফোন খুব বেশি গরম হয়ে যায়, তাই ঠাণ্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ফোন এখন ভালভাবে কাজ করছে।\n\nআপনার ফোন খুব বেশি গরম হয়ে যেতে পারে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করেন যেটি আপনার ফোনের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করেন\n • অনেক বেশি তাপমাত্রায় ফোন ব্যবহার করেন"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"আপনার ডিভাইস খুব বেশি গরম হয়ে যায়, তাই ঠাণ্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ডিভাইস এখন ভালভাবে কাজ করছে।\n\nআপনার ডিভাইস খুব বেশি গরম হয়ে যেতে পারে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করেন যেটি আপনার ডিভাইসের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করেন\n • অনেক বেশি তাপমাত্রায় ডিভাইস ব্যবহার করেন"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"আপনার ট্যাবলেট খুব বেশি গরম হয়ে যায়, তাই ঠাণ্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ট্যাবলেট এখন ভালভাবে কাজ করছে।\n\nআপনার ট্যাবলেট খুব বেশি গরম হয়ে যেতে পারে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করেন যেটি আপনার ট্যাবলেটের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করেন\n • অনেক বেশি তাপমাত্রায় ট্যাবলেট ব্যবহার করেন"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ফোন গরম হয়ে গেছে"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ডিভাইস গরম হয়ে গেছে"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ট্যাবলেট গরম হয়ে গেছে"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ফোন ঠাণ্ডা না হওয়া পর্যন্ত কিছু ফিচার কাজ করতে পারে না।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ডিভাইস ঠাণ্ডা না হওয়া পর্যন্ত কিছু ফিচার কাজ করতে পারে না।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ট্যাবলেট ঠাণ্ডা না হওয়া পর্যন্ত কিছু ফিচার কাজ করতে পারে না।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"আপনার ফোনটি অটোমেটিক ঠাণ্ডা হওয়ার চেষ্টা করবে। আপনি তবুও ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে।\n\nফোন পুরোপুরি ঠাণ্ডা হয়ে গেলে, এটি ভালভাবে চলবে।"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"আপনার ডিভাইস অটোমেটিক ঠাণ্ডা হওয়ার চেষ্টা করবে। আপনি তবুও ডিভাইস ব্যবহার করতে পারবেন, কিন্তু এটি একটু ধীরে চলতে পারে।\n\nডিভাইস পুরোপুরি ঠাণ্ডা হয়ে গেলে, এটি ভালভাবে চলবে।"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"আপনার ট্যাবলেট অটোমেটিক ঠাণ্ডা হওয়ার চেষ্টা করবে। আপনি তবুও ট্যাবলেট ব্যবহার করতে পারবেন, কিন্তু এটি একটু ধীরে চলতে পারে।\n\nট্যাবলেট পুরোপুরি ঠাণ্ডা হয়ে গেলে, এটি ভালভাবে চলবে।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"\'পাওয়ার\' বোতামের উপরে ফিঙ্গারপ্রিন্ট সেন্সর দেওয়া হয়েছে। ট্যাবলেটের প্রান্তে একটু বাইরে বেরিয়ে থাকা ভলিউমের বোতামের ঠিক পাশে এই ফ্ল্যাট বোতামটি আপনি খুঁজে পাবেন।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"\'পাওয়ার\' বোতামের উপরে ফিঙ্গারপ্রিন্ট সেন্সর দেওয়া হয়েছে। ডিভাইসের সাইডে একটু বাইরে বেরিয়ে থাকা ভলিউমের বোতামের ঠিক পাশে এই ফ্ল্যাট বোতামটি আপনি খুঁজে পাবেন।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"\'পাওয়ার\' বোতামের উপরে ফিঙ্গারপ্রিন্ট সেন্সর দেওয়া হয়েছে। ফোনের প্রান্তে একটু বাইরে বেরিয়ে থাকা ভলিউমের বোতামের ঠিক পাশে এই ফ্ল্যাট বোতামটি আপনি খুঁজে পাবেন।"</string>
diff --git a/packages/SystemUI/res-product/values-bs/strings.xml b/packages/SystemUI/res-product/values-bs/strings.xml
index 576fac4..1c1316f 100644
--- a/packages/SystemUI/res-product/values-bs/strings.xml
+++ b/packages/SystemUI/res-product/values-bs/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Pokušali ste neispravno otključati telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Radni profil će se ukloniti i svi podaci s profila će se izbrisati."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate tablet pomoću računa e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. U slučaju još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate telefon pomoću računa e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon se isključio zbog pregrijavanja"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Uređaj se isključio zbog pregrijavanja"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet se isključio zbog pregrijavanja"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Vaš telefon sada radi normalno.\nDodirnite za više informacija"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Vaš uređaj sada radi normalno.\nDodirnite za više informacija"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Vaš tablet sada radi normalno.\nDodirnite za više informacija"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Vaš telefon se pregrijao, pa se isključio da se ohladi. Telefon sada radi normalno.\n\nTelefon se može pregrijati ako:\n • koristite aplikacije koje troše puno resursa (kao što su aplikacije za igranje, videozapise ili navigaciju)\n • preuzimate ili otpremate velike fajlove\n • koristite telefon na visokim temperaturama"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Vaš uređaj se pregrijao, pa se isključio da se ohladi. Uređaj sada radi normalno.\n\nUređaj se može pregrijati ako:\n • koristite aplikacije koje troše puno resursa (kao što su aplikacije za igranje, videozapise ili navigaciju)\n • preuzimate ili otpremate velike fajlove\n • koristite uređaj na visokim temperaturama"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Vaš tablet se pregrijao, pa se isključio da se ohladi. Tablet sada radi normalno.\n\nTablet se može pregrijati ako:\n • koristite aplikacije koje troše puno resursa (kao što su aplikacije za igranje, videozapise ili navigaciju)\n • preuzimate ili otpremate velike fajlove\n • koristite tablet na visokim temperaturama"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon se zagrijava"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Uređaj se zagrijava"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet se zagrijava"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Neke funkcije su ograničene dok se telefon hladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Neke funkcije su ograničene dok se uređaj hladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Neke funkcije su ograničene dok se tablet hladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Vaš telefon će se automatski pokušati ohladiti. I dalje možete koristiti telefon, ali će možda sporije raditi.\n\nNakon što se ohladi, telefon će raditi normalno."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Uređaj će se automatski pokušati ohladiti. I dalje možete koristiti uređaj, ali će možda sporije raditi.\n\nNakon što se ohladi, uređaj će raditi normalno."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablet će se automatski pokušati ohladiti. I dalje možete koristiti tablet, ali će možda sporije raditi.\n\nNakon što se ohladi, tablet će raditi normalno."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor za otisak prsta je na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na rubu tableta."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor za otisak prsta je na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na rubu uređaja."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor za otisak prsta je na dugmetu za uključivanje. To je ravno dugme pored izdignutog dugmeta za jačinu zvuka na rubu telefona."</string>
diff --git a/packages/SystemUI/res-product/values-ca/strings.xml b/packages/SystemUI/res-product/values-ca/strings.xml
index d8d4a47..4b84a6b 100644
--- a/packages/SystemUI/res-product/values-ca/strings.xml
+++ b/packages/SystemUI/res-product/values-ca/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. El perfil de treball se suprimirà, juntament amb totes les dades que contingui."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"El telèfon s\'ha apagat per la calor"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"El dispositiu s\'ha apagat per la calor"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"La tauleta s\'ha apagat per la calor"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Ara el telèfon funciona amb normalitat.\nToca per obtenir més informació."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Ara el dispositiu funciona amb normalitat.\nToca per obtenir més informació."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Ara la tauleta funciona amb normalitat.\nToca per obtenir més informació."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"El telèfon s\'havia sobreescalfat i s\'ha apagat per refredar-se. Ara funciona amb normalitat.\n\nEs pot sobreescalfar si:\n • Utilitzes aplicacions que consumeixen molts recursos (com ara, videojocs, vídeos o aplicacions de navegació).\n • Baixes o penges fitxers grans.\n • L\'utilitzes amb temperatures altes."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"El dispositiu s\'havia sobreescalfat i s\'ha apagat per refredar-se. Ara funciona amb normalitat.\n\nEs pot sobreescalfar si:\n • Utilitzes aplicacions que consumeixen molts recursos (com ara videojocs, vídeos o aplicacions de navegació).\n • Baixes o penges fitxers grans.\n • L\'utilitzes amb temperatures altes."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"La tauleta s\'havia sobreescalfat i s\'ha apagat per refredar-se. Ara funciona amb normalitat.\n\nEs pot sobreescalfar si:\n • Utilitzes aplicacions que consumeixen molts recursos (com ara videojocs, vídeos o aplicacions de navegació).\n • Baixes o penges fitxers grans.\n • L\'utilitzes amb temperatures altes."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"El telèfon s\'està escalfant"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"El dispositiu s\'està escalfant"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"La tauleta s\'està escalfant"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Algunes funcions estan limitades mentre el telèfon es refreda.\nToca per obtenir més informació."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Algunes funcions estan limitades mentre el dispositiu es refreda.\nToca per obtenir més informació."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Algunes funcions estan limitades mentre la tauleta es refreda.\nToca per obtenir més informació."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"El telèfon provarà de refredar-se automàticament. Podràs continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"El dispositiu provarà de refredar-se automàticament. Pots continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"La tauleta provarà de refredar-se automàticament. Pots continuar utilitzant-la, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"El sensor d\'empremtes digitals es troba al botó d\'engegada. És el botó pla situat al costat del botó de volum amb relleu al lateral de la tauleta."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"El sensor d\'empremtes digitals es troba al botó d\'engegada. És el botó pla situat al costat del botó de volum amb relleu al lateral del dispositiu."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"El sensor d\'empremtes digitals es troba al botó d\'engegada. És el botó pla situat al costat del botó de volum amb relleu al lateral del telèfon."</string>
diff --git a/packages/SystemUI/res-product/values-cs/strings.xml b/packages/SystemUI/res-product/values-cs/strings.xml
index 47881bd..ffefb98 100644
--- a/packages/SystemUI/res-product/values-cs/strings.xml
+++ b/packages/SystemUI/res-product/values-cs/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Již <xliff:g id="NUMBER">%d</xliff:g>krát jste se pokusili odemknout telefon nesprávným způsobem. Pracovní profil bude odstraněn, čímž budou smazána všechna jeho data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně zadali své bezpečnostní gesto. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon se vypnul z důvodu zahřátí"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Zařízení se vypnulo z důvodu zahřátí"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet se vypnul z důvodu zahřátí"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Nyní telefon funguje jako obvykle.\nKlepnutím zobrazíte další informace"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Nyní zařízení funguje jako obvykle.\nKlepnutím zobrazíte další informace"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Nyní tablet funguje jako obvykle.\nKlepnutím zobrazíte další informace"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon byl příliš zahřátý, proto se vypnul, aby vychladl. Nyní telefon funguje jako obvykle.\n\nTelefon se může příliš zahřát v těchto případech:\n • používání náročných aplikací (např. her, videí nebo navigace),\n • stahování nebo nahrávání velkých souborů,\n • používání telefonu při vysokých teplotách."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Zařízení bylo příliš zahřáté, proto se vypnulo, aby vychladlo. Nyní zařízení funguje jako obvykle.\n\nZařízení se může příliš zahřát v těchto případech:\n • používání náročných aplikací (např. her, videí nebo navigace),\n • stahování nebo nahrávání velkých souborů,\n • používání zařízení při vysokých teplotách."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablet byl příliš zahřátý, proto se vypnul, aby vychladl. Nyní tablet funguje jako obvykle.\n\nTablet se může příliš zahřát v těchto případech:\n • používání náročných aplikací (např. her, videí nebo navigace),\n • stahování nebo nahrávání velkých souborů,\n • používání tabletu při vysokých teplotách."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon se zahřívá"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Zařízení se zahřívá"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet se zahřívá"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Některé funkce jsou při chladnutí telefonu omezeny.\nKlepnutím zobrazíte další informace"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Některé funkce jsou při chladnutí zařízení omezeny.\nKlepnutím zobrazíte další informace"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Některé funkce jsou při chladnutí tabletu omezeny.\nKlepnutím zobrazíte další informace"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefon se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž telefon vychladne, bude fungovat normálně."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Zařízení se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž zařízení vychladne, bude fungovat normálně."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablet se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž tablet vychladne, bude fungovat normálně."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Snímač otisků prstů je na vypínači. Je to ploché tlačítko vedle vystouplého tlačítka hlasitosti na hraně tabletu."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Snímač otisků prstů je na vypínači. Je to ploché tlačítko vedle vystouplého tlačítka hlasitosti na hraně zařízení."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Snímač otisků prstů je na vypínači. Je to ploché tlačítko vedle vystouplého tlačítka hlasitosti na hraně telefonu."</string>
diff --git a/packages/SystemUI/res-product/values-da/strings.xml b/packages/SystemUI/res-product/values-da/strings.xml
index 47531e7..9bed837 100644
--- a/packages/SystemUI/res-product/values-da/strings.xml
+++ b/packages/SystemUI/res-product/values-da/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har forsøgt at låse telefonen op med den forkerte adgangskode <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket sletter alle profildata."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din tablet op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykkede forsøg bliver du bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefonen slukkede pga. varme"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Enheden slukkede pga. varme"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Din tablet slukkede pga. varme"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Din telefon kører nu normalt.\nTryk for at få flere oplysninger"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Din enhed kører nu normalt.\nTryk for at få flere oplysninger"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Din tablet kører nu normalt.\nTryk for at få flere oplysninger"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Din telefon var blevet for varm, så den slukkede for at køle ned. Din telefon kører nu igen normalt. \n\nDin telefon kan blive for varm, hvis du:\n • Bruger ressourcekrævende apps (f.eks. spil, video eller navigation)\n • Downloader eller uploader store filer\n • Bruger din telefon i varme omgivelser"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Din enhed var blevet for varm, så den slukkede for at køle ned. Din enhed kører nu igen normalt. \n\nDin enhed kan blive for varm, hvis du:\n • Bruger ressourcekrævende apps (f.eks. spil, video eller navigation)\n • Downloader eller uploader store filer\n • Bruger din enhed i varme omgivelser"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Din tablet var blevet for varm, så den slukkede for at køle ned. Din tablet kører nu igen normalt. \n\nDin tablet kan blive for varm, hvis du:\n • Bruger ressourcekrævende apps (f.eks. spil, video eller navigation)\n • Downloader eller uploader store filer\n • Bruger din tablet i varme omgivelser"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefonen er ved at blive varm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Enheden er ved at blive varm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tabletten er ved at blive varm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Nogle funktioner er begrænsede, mens telefonen køler ned.\nTryk for at få flere oplysninger"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Nogle funktioner er begrænsede, mens enheden køler ned.\nTryk for at få flere oplysninger"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Nogle funktioner er begrænsede, mens din tablet køler ned.\nTryk for at få flere oplysninger"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Din telefon forsøger automatisk at køle sig selv ned. Du kan stadig bruge telefonen, men den kører muligvis langsommere end normalt.\n\nNår din telefon er kølet ned, fungerer den normalt igen."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Din enhed forsøger automatisk at køle sig selv ned. Du kan stadig bruge din enhed, men den kører muligvis langsommere end normalt.\n\nNår din enhed er kølet ned, fungerer den normalt igen."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Din tablet forsøger automatisk at køle sig selv ned. Du kan stadig bruge din tablet, men den kører muligvis langsommere end normalt.\n\nNår din tablet er kølet ned, fungerer den normalt igen."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingeraftrykssensoren sidder på afbryderknappen. Det er den flade knap ved siden af den hævede lydstyrkeknap på siden af din tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingeraftrykssensoren sidder på afbryderknappen. Det er den flade knap ved siden af den hævede lydstyrkeknap på siden af enheden."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingeraftrykssensoren sidder på afbryderknappen. Det er den flade knap ved siden af den hævede lydstyrkeknap på siden af telefonen."</string>
diff --git a/packages/SystemUI/res-product/values-de/strings.xml b/packages/SystemUI/res-product/values-de/strings.xml
index 9c0b768..80389a4 100644
--- a/packages/SystemUI/res-product/values-de/strings.xml
+++ b/packages/SystemUI/res-product/values-de/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du hast <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Smartphone zu entsperren. Das Arbeitsprofil wird nun entfernt und alle Profildaten werden gelöscht."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Smartphone mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden noch einmal."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Smartphone wegen Überhitzung ausgeschaltet"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Gerät wegen Überhitzung ausgeschaltet"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet wegen Überhitzung ausgeschaltet"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Dein Smartphone funktioniert jetzt wieder normal.\nFür mehr Informationen tippen."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Dein Gerät funktioniert jetzt wieder normal.\nFür mehr Informationen tippen."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Dein Tablet funktioniert jetzt wieder normal.\nFür mehr Informationen tippen."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Dein Smartphone war zu heiß und wurde zum Abkühlen ausgeschaltet. Nun funktioniert es wieder normal.\n\nMögliche Ursachen:\n • Verwendung ressourcenintensiver Apps, z. B. Spiele-, Video- oder Navigations-Apps\n • Download oder Upload großer Dateien\n • Verwendung des Smartphones bei hohen Temperaturen"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Dein Gerät war zu heiß und wurde zum Abkühlen ausgeschaltet. Nun funktioniert es wieder normal.\n\nMögliche Ursachen:\n • Verwendung ressourcenintensiver Apps, z. B. Spiele-, Video- oder Navigations-Apps\n • Download oder Upload großer Dateien\n • Verwendung des Geräts bei hohen Temperaturen"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Dein Tablet war zu heiß und wurde zum Abkühlen ausgeschaltet. Nun funktioniert es wieder normal.\n\nMögliche Ursachen:\n • Verwendung ressourcenintensiver Apps, z. B. Spiele-, Video- oder Navigations-Apps\n • Download oder Upload großer Dateien\n • Verwendung des Tablets bei hohen Temperaturen"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Smartphone wird warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Gerät wird warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet wird warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Einige Funktionen sind während der Abkühlphase des Smartphones eingeschränkt.\nFür mehr Informationen tippen."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Einige Funktionen sind während der Abkühlphase des Geräts eingeschränkt.\nFür mehr Informationen tippen."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Einige Funktionen sind während der Abkühlphase des Tablets eingeschränkt.\nFür mehr Informationen tippen."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Dein Smartphone kühlt sich automatisch ab. Du kannst es weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Smartphone abgekühlt ist, funktioniert es wieder normal."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Dein Gerät kühlt sich automatisch ab. Du kannst es weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Gerät abgekühlt ist, funktioniert es wieder normal."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Dein Tablet kühlt sich automatisch ab. Du kannst es weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Tablet abgekühlt ist, funktioniert es wieder normal."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Der Fingerabdrucksensor befindet sich auf der Ein-/Aus-Taste. Das ist die flache Taste neben der erhöhten Lautstärketaste am Rand des Tablets."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Der Fingerabdrucksensor befindet sich auf der Ein-/Aus-Taste. Das ist die flache Taste neben der erhöhten Lautstärketaste am Rand des Geräts."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Der Fingerabdrucksensor befindet sich auf der Ein-/Aus-Taste. Das ist die flache Taste neben der erhöhten Lautstärketaste am Rand des Smartphones."</string>
diff --git a/packages/SystemUI/res-product/values-el/strings.xml b/packages/SystemUI/res-product/values-el/strings.xml
index 139fa04..67bdbcf 100644
--- a/packages/SystemUI/res-product/values-el/strings.xml
+++ b/packages/SystemUI/res-product/values-el/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί και θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το tablet με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ακόμα ανεπιτυχείς προσπάθειες, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Το τηλέφωνο απενεργοποιήθηκε λόγω ζέστης"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Η συσκευή απενεργοποιήθηκε λόγω ζέστης"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Το tablet απενεργοποιήθηκε λόγω ζέστης"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Το τηλέφωνο λειτουργεί πλέον κανονικά.\nΠατήστε για περισσότερες πληροφορίες"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Η συσκευή λειτουργεί πλέον κανονικά.\nΠατήστε για περισσότερες πληροφορίες"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Το tablet λειτουργεί πλέον κανονικά.\nΠατήστε για περισσότερες πληροφορίες"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Η θερμοκρασία του τηλεφώνου είναι πολύ υψηλή και απενεργοποιήθηκε για να κρυώσει. Πλέον, το τηλέφωνο λειτουργεί κανονικά.\n\nΗ θερμοκρασία του τηλεφώνου ενδέχεται να ανέβει κατά τη:\n • Χρήση εφαρμογών υψηλής κατανάλωσης πόρων (όπως gaming, βίντεο ή περιήγησης)\n • Λήψη ή μεταφόρτωση μεγάλων αρχείων\n • Χρήση του τηλεφώνου σε υψηλές θερμοκρασίες"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Η θερμοκρασία της συσκευής είναι πολύ υψηλή και απενεργοποιήθηκε για να κρυώσει. Πλέον, η συσκευή λειτουργεί κανονικά.\n\nΗ θερμοκρασία της συσκευής ενδέχεται να ανέβει κατά τη:\n • Χρήση εφαρμογών υψηλής κατανάλωσης πόρων (όπως gaming, βίντεο ή περιήγησης)\n • Λήψη ή μεταφόρτωση μεγάλων αρχείων\n • Χρήση της συσκευής σε υψηλές θερμοκρασίες"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Η θερμοκρασία του tablet είναι πολύ υψηλή και απενεργοποιήθηκε για να κρυώσει. Πλέον, το tablet λειτουργεί κανονικά.\n\nΗ θερμοκρασία του tablet ενδέχεται να ανέβει κατά τη:\n • Χρήση εφαρμογών υψηλής κατανάλωσης πόρων (όπως gaming, βίντεο ή περιήγησης)\n • Λήψη ή μεταφόρτωση μεγάλων αρχείων\n • Χρήση του tablet σε υψηλές θερμοκρασίες"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Το τηλέφωνο θερμαίνεται"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Η συσκευή θερμαίνεται"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Το tablet θερμαίνεται"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας του τηλεφώνου.\nΠατήστε για περισσότερες πληροφορίες"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας της συσκευής.\nΠατήστε για περισσότερες πληροφορίες"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας του tablet.\nΠατήστε για περισσότερες πληροφορίες"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Το τηλέφωνό σας θα προσπαθήσει αυτόματα να κρυώσει. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του τηλεφώνου σας, θα λειτουργεί ξανά κανονικά."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Η συσκευή σας θα προσπαθήσει αυτόματα να κρυώσει. Μπορείτε να εξακολουθήσετε να τη χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία της συσκευής σας, θα λειτουργεί ξανά κανονικά."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Το tablet σας θα προσπαθήσει αυτόματα να κρυώσει. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του tablet σας, θα λειτουργεί ξανά κανονικά."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Ο αισθητήρας δακτυλικών αποτυπωμάτων βρίσκεται στο κουμπί λειτουργίας. Είναι το επίπεδο κουμπί δίπλα στο ανυψωμένο κουμπί έντασης ήχου στο άκρο του tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Ο αισθητήρας δακτυλικών αποτυπωμάτων βρίσκεται στο κουμπί λειτουργίας. Είναι το επίπεδο κουμπί δίπλα στο ανυψωμένο κουμπί έντασης ήχου στο άκρο της συσκευής."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Ο αισθητήρας δακτυλικών αποτυπωμάτων βρίσκεται στο κουμπί λειτουργίας. Είναι το επίπεδο κουμπί δίπλα στο ανυψωμένο κουμπί έντασης ήχου στο άκρο του τηλεφώνου."</string>
diff --git a/packages/SystemUI/res-product/values-en-rAU/strings.xml b/packages/SystemUI/res-product/values-en-rAU/strings.xml
index 6356fc2..1373251 100644
--- a/packages/SystemUI/res-product/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rAU/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Phone turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Device turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet turned off due to heat"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Your phone is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Your device is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Your tablet is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Your device was too hot, so it turned off to cool down. Your device is now running normally.\n\nYour device may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your device in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Your tablet was too hot, so it turned off to cool down. Your tablet is now running normally.\n\nYour tablet may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your tablet in high temperatures"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Phone is getting warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Device is getting warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet is getting warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Some features limited while phone cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Some features limited while device cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Some features limited while tablet cools down.\nTap for more info"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Your device will automatically try to cool down. You can still use your device, but it may run slower.\n\nOnce your device has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Your tablet will automatically try to cool down. You can still use your tablet, but it may run slower.\n\nOnce your tablet has cooled down, it will run normally."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
diff --git a/packages/SystemUI/res-product/values-en-rCA/strings.xml b/packages/SystemUI/res-product/values-en-rCA/strings.xml
index fb7aa72..eaa5de0 100644
--- a/packages/SystemUI/res-product/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rCA/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Phone turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Device turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet turned off due to heat"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Your phone is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Your device is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Your tablet is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Your device was too hot, so it turned off to cool down. Your device is now running normally.\n\nYour device may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your device in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Your tablet was too hot, so it turned off to cool down. Your tablet is now running normally.\n\nYour tablet may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your tablet in high temperatures"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Phone is getting warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Device is getting warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet is getting warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Some features limited while phone cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Some features limited while device cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Some features limited while tablet cools down.\nTap for more info"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Your device will automatically try to cool down. You can still use your device, but it may run slower.\n\nOnce your device has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Your tablet will automatically try to cool down. You can still use your tablet, but it may run slower.\n\nOnce your tablet has cooled down, it will run normally."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the device."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It\'s the flat button next to the raised volume button on the edge of the phone."</string>
diff --git a/packages/SystemUI/res-product/values-en-rGB/strings.xml b/packages/SystemUI/res-product/values-en-rGB/strings.xml
index 6356fc2..1373251 100644
--- a/packages/SystemUI/res-product/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rGB/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Phone turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Device turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet turned off due to heat"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Your phone is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Your device is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Your tablet is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Your device was too hot, so it turned off to cool down. Your device is now running normally.\n\nYour device may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your device in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Your tablet was too hot, so it turned off to cool down. Your tablet is now running normally.\n\nYour tablet may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your tablet in high temperatures"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Phone is getting warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Device is getting warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet is getting warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Some features limited while phone cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Some features limited while device cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Some features limited while tablet cools down.\nTap for more info"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Your device will automatically try to cool down. You can still use your device, but it may run slower.\n\nOnce your device has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Your tablet will automatically try to cool down. You can still use your tablet, but it may run slower.\n\nOnce your tablet has cooled down, it will run normally."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
diff --git a/packages/SystemUI/res-product/values-en-rIN/strings.xml b/packages/SystemUI/res-product/values-en-rIN/strings.xml
index 6356fc2..1373251 100644
--- a/packages/SystemUI/res-product/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rIN/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Phone turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Device turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet turned off due to heat"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Your phone is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Your device is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Your tablet is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Your device was too hot, so it turned off to cool down. Your device is now running normally.\n\nYour device may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your device in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Your tablet was too hot, so it turned off to cool down. Your tablet is now running normally.\n\nYour tablet may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your tablet in high temperatures"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Phone is getting warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Device is getting warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet is getting warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Some features limited while phone cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Some features limited while device cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Some features limited while tablet cools down.\nTap for more info"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Your device will automatically try to cool down. You can still use your device, but it may run slower.\n\nOnce your device has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Your tablet will automatically try to cool down. You can still use your tablet, but it may run slower.\n\nOnce your tablet has cooled down, it will run normally."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
diff --git a/packages/SystemUI/res-product/values-en-rXC/strings.xml b/packages/SystemUI/res-product/values-en-rXC/strings.xml
index 4a7d0ad..b1a5613 100644
--- a/packages/SystemUI/res-product/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rXC/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The work profile will be removed, which will delete all profile data."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Phone turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Device turned off due to heat"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet turned off due to heat"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Your phone is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Your device is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Your tablet is now running normally.\nTap for more info"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Your device was too hot, so it turned off to cool down. Your device is now running normally.\n\nYour device may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your device in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Your tablet was too hot, so it turned off to cool down. Your tablet is now running normally.\n\nYour tablet may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your tablet in high temperatures"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Phone is getting warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Device is getting warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet is getting warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Some features limited while phone cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Some features limited while device cools down.\nTap for more info"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Some features limited while tablet cools down.\nTap for more info"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Your device will automatically try to cool down. You can still use your device, but it may run slower.\n\nOnce your device has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Your tablet will automatically try to cool down. You can still use your tablet, but it may run slower.\n\nOnce your tablet has cooled down, it will run normally."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the device."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"The fingerprint sensor is on the power button. It’s the flat button next to the raised volume button on the edge of the phone."</string>
diff --git a/packages/SystemUI/res-product/values-es-rUS/strings.xml b/packages/SystemUI/res-product/values-es-rUS/strings.xml
index 3a22304..7ee96b2 100644
--- a/packages/SystemUI/res-product/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-product/values-es-rUS/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se quitará el perfil de trabajo, lo que borrará todos los datos asociados."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Dibujaste el patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees la tablet mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Dibujaste el patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees el dispositivo mediante una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Se apagó el tel. debido a alta temp."</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Se apagó el disp. debido a alta temp."</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Se apagó la tablet debido a alta temp."</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Tu teléfono ahora se ejecuta con normalidad.\nPresiona para obtener más información"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Tu dispositivo ahora se ejecuta con normalidad.\nPresiona para obtener más información"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tu tablet ahora se ejecuta con normalidad.\nPresiona para obtener más información"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Tu teléfono estaba muy caliente y se apagó para enfriarse. Ya funciona correctamente.\n\nTu teléfono puede calentarse en los siguientes casos:\n • Si usas apps que consumen muchos recursos (como juegos, videos o navegación).\n • Si subes o descargas archivos grandes.\n • Si usas el teléfono en condiciones de temperatura alta."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Tu dispositivo estaba muy caliente y se apagó para enfriarse. Ya funciona correctamente.\n\nTu dispositivo puede calentarse en los siguientes casos:\n • Si usas apps que consumen muchos recursos (como juegos, videos o navegación).\n • Si subes o descargas archivos grandes.\n • Si usas el dispositivo en condiciones de temperatura alta."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tu tablet estaba muy caliente y se apagó para enfriarse. Ya funciona correctamente.\n\nTu tablet puede calentarse en los siguientes casos:\n • Si usas apps que consumen muchos recursos (como juegos, videos o navegación).\n • Si subes o descargas archivos grandes.\n • Si usas la tablet en condiciones de temperatura alta."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"El teléfono se está calentando"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"El disp. se está calentando"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"La tablet se está calentando"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Algunas funciones se limitan durante el enfriamiento del teléfono.\nPresiona para obtener más información"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Algunas funciones se limitan durante el enfriamiento del dispositivo.\nPresiona para obtener más información"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Algunas funciones se limitan durante el enfriamiento de la tablet.\nPresiona para obtener más información"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Tu teléfono intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar con normalidad."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Tu dispositivo intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar con normalidad."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tu tablet intentará enfriarse automáticamente. Podrás usarla, pero es posible que funcione más lenta.\n\nUna vez que se haya enfriado, volverá a funcionar con normalidad."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"El sensor de huellas dactilares está en el botón de encendido. Es el botón plano que está junto al botón de volumen en relieve, en el borde de la tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"El sensor de huellas dactilares está en el botón de encendido. Es el botón plano que está junto al botón de volumen en relieve, en el borde del dispositivo."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"El sensor de huellas dactilares está en el botón de encendido. Es el botón plano que está junto al botón de volumen en relieve, en el borde del teléfono."</string>
diff --git a/packages/SystemUI/res-product/values-es/strings.xml b/packages/SystemUI/res-product/values-es/strings.xml
index 744761d..d39c6ed 100644
--- a/packages/SystemUI/res-product/values-es/strings.xml
+++ b/packages/SystemUI/res-product/values-es/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Se quitará este perfil de trabajo y se eliminarán todos sus datos."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Has dibujado un patrón de desbloqueo incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te pedirá que desbloquees el tablet con una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Has dibujado un patrón de desbloqueo incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te pedirá que desbloquees el teléfono con una cuenta de correo electrónico.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Teléfono apagado por calor"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Dispositivo apagado por calor"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet apagada por calor"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"El teléfono ya funciona con normalidad.\nToca para ver más información."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"El dispositivo ya funciona con normalidad.\nToca para ver más información."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"La tablet ya funciona con normalidad.\nToca para ver más información."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"El teléfono se calentó demasiado, así que se apagó para enfriarse. Ahora funciona con normalidad.\n\nTu teléfono puede calentarse demasiado si:\n • Usas aplicaciones que consumen muchos recursos (como aplicaciones de juegos, vídeos o navegación)\n • Descargas o subes archivos de gran tamaño\n • Lo usas a altas temperaturas"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"El dispositivo se calentó demasiado, así que se apagó para enfriarse. Ahora funciona con normalidad.\n\nTu dispositivo puede calentarse demasiado si:\n • Usas aplicaciones que consumen muchos recursos (como aplicaciones de juegos, vídeos o navegación)\n • Descargas o subes archivos de gran tamaño\n • Lo usas a altas temperaturas"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"La tablet se calentó demasiado, así que se apagó para enfriarse. Ahora funciona con normalidad.\n\nTu tablet puede calentarse demasiado si:\n • Usas aplicaciones que consumen muchos recursos (como aplicaciones de juegos, vídeos o navegación)\n • Descargas o subes archivos de gran tamaño\n • La usas a altas temperaturas"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"El teléfono se está calentando"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"El dispositivo se está calentando"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"La tablet se está calentando"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Se han limitado algunas funciones mientras el teléfono se enfría.\nToca para ver más información."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Se han limitado algunas funciones mientras el dispositivo se enfría.\nToca para ver más información."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Se han limitado algunas funciones mientras la tablet se enfría.\nToca para ver más información."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"El teléfono intentará enfriarse automáticamente. Puedes seguir usándolo, pero es posible que funcione más lento.\n\nUna vez que el teléfono se haya enfriado, funcionará con normalidad."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"El dispositivo intentará enfriarse automáticamente. Puedes seguir usándolo, pero es posible que funcione más lento.\n\nUna vez que el dispositivo se haya enfriado, funcionará con normalidad."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"La tablet intentará enfriarse automáticamente. Puedes seguir usándola, pero es posible que funcione más lenta.\n\nUna vez que la tablet se haya enfriado, funcionará con normalidad."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"El sensor de huellas digitales está en el botón de encendido. Es el botón plano situado junto al botón de volumen con relieve cerca de una de la esquinas de la tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"El sensor de huellas digitales está en el botón de encendido. Es el botón plano situado junto al botón de volumen con relieve en el lateral del dispositivo."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"El sensor de huellas digitales está en el botón de encendido. Es el botón plano situado junto al botón de volumen con relieve en el lateral del teléfono."</string>
diff --git a/packages/SystemUI/res-product/values-et/strings.xml b/packages/SystemUI/res-product/values-et/strings.xml
index 4d8af24..8cd4ae6 100644
--- a/packages/SystemUI/res-product/values-et/strings.xml
+++ b/packages/SystemUI/res-product/values-et/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda telefoni valesti avada. Tööprofiil eemaldatakse ja kõik profiiliandmed kustutatakse."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon lülitati kuuma tõttu välja"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Seade lülitati kuuma tõttu välja"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tahvelarvuti lülitati kuuma tõttu välja"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefon töötab nüüd tavapäraselt.\nPuudutage lisateabe saamiseks."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Seade töötab nüüd tavapäraselt.\nPuudutage lisateabe saamiseks."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tahvelarvuti töötab nüüd tavapäraselt.\nPuudutage lisateabe saamiseks."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon oli liiga kuum, seetõttu lülitus see jahtumiseks välja. Telefon töötab nüüd tavapäraselt.\n\nTelefon võib kuumaks minna:\n • ressursse koormavate rakenduste kasutamisel (nt mängu-, video- või navigatsioonirakendused)\n • suurte failide alla-/üleslaadimisel\n • telefoni kasutamisel kõrgel temperatuuril"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Seade oli liiga kuum, seetõttu lülitus see jahtumiseks välja. Seade töötab nüüd tavapäraselt.\n\nSeade võib kuumaks minna:\n • ressursse koormavate rakenduste kasutamisel (nt mängu-, video- või navigatsioonirakendused)\n • suurte failide alla-/üleslaadimisel\n • seadme kasutamisel kõrgel temperatuuril"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tahvelarvuti oli liiga kuum, seetõttu lülitus see jahtumiseks välja. Tahvelarvuti töötab nüüd tavapäraselt.\n\nTahvelarvuti võib kuumaks minna:\n • ressursse koormavate rakenduste kasutamisel (nt mängu-, video- või navigatsioonirakendused)\n • suurte failide alla-/üleslaadimisel\n • tahvelarvuti kasutamisel kõrgel temperatuuril"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon soojeneb"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Seade soojeneb"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tahvelarvuti soojeneb"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Mõned funktsioonid on piiratud, kuni telefon jahtub.\nPuudutage lisateabe saamiseks."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Mõned funktsioonid on piiratud, kuni seade jahtub.\nPuudutage lisateabe saamiseks."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Mõned funktsioonid on piiratud, kuni tahvelarvuti jahtub.\nPuudutage lisateabe saamiseks."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Teie telefon proovib automaatselt maha jahtuda. Saate telefoni ikka kasutada, kuid see võib olla aeglasem.\n\nKui telefon on jahtunud, töötab see tavapäraselt."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Teie seade proovib automaatselt maha jahtuda. Saate seadet ikka kasutada, kuid see võib olla aeglasem.\n\nKui seade on jahtunud, töötab see tavapäraselt."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Teie tahvelarvuti proovib automaatselt maha jahtuda. Saate tahvelarvutit ikka kasutada, kuid see võib olla aeglasem.\n\nKui tahvelarvuti on jahtunud, töötab see tavapäraselt."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sõrmejäljeandur asub toitenupul. See on tahvelarvuti küljel helitugevuse kõrgendatud nupu kõrval olev lame nupp."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sõrmejäljeandur asub toitenupul. See on seadme küljel helitugevuse kõrgendatud nupu kõrval olev lame nupp."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sõrmejäljeandur asub toitenupul. See on telefoni küljel helitugevuse kõrgendatud nupu kõrval olev lame nupp."</string>
diff --git a/packages/SystemUI/res-product/values-eu/strings.xml b/packages/SystemUI/res-product/values-eu/strings.xml
index dcb1ead..032811c 100644
--- a/packages/SystemUI/res-product/values-eu/strings.xml
+++ b/packages/SystemUI/res-product/values-eu/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Gehiegi berotu delako itzali da telefonoa"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Gehiegi berotu delako itzali da gailua"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Gehiegi berotu delako itzali da tableta"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Orain, ohi bezala funtzionatzen du telefonoak.\nInformazio gehiago lortzeko, sakatu hau"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Orain, ohi bezala funtzionatzen du gailuak.\nInformazio gehiago lortzeko, sakatu hau"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Orain, ohi bezala funtzionatzen du tabletak.\nInformazio gehiago lortzeko, sakatu hau"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefonoa gehiegi berotu denez, itzali egin da hoztu ahal izateko. Orain, ohi bezala funtzionatzen du.\n\nBerotzeko arrazoi posibleak:\n • Baliabide asko behar dituzten aplikazioak erabiltzea (adibidez, jokoak, bideoak edo nabigazio-aplikazioak).\n • Fitxategi handiak deskargatzea edo kargatzea.\n • Telefonoa tenperatura altuak daudenean erabiltzea."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Gailua gehiegi berotu denez, itzali egin da hoztu ahal izateko. Orain, ohi bezala funtzionatzen du.\n\nBerotzeko arrazoi posibleak:\n • Baliabide asko behar dituzten aplikazioak erabiltzea (adibidez, jokoak, bideoak edo nabigazio-aplikazioak).\n • Fitxategi handiak deskargatzea edo kargatzea.\n • Gailua tenperatura altuak daudenean erabiltzea."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tableta gehiegi berotu denez, itzali egin da hoztu ahal izateko. Orain, ohi bezala funtzionatzen du.\n\nBerotzeko arrazoi posibleak:\n • Baliabide asko behar dituzten aplikazioak erabiltzea (adibidez, jokoak, bideoak edo nabigazio-aplikazioak).\n • Fitxategi handiak deskargatzea edo kargatzea.\n • Tableta tenperatura altuak daudenean erabiltzea."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefonoa berotzen ari da"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Gailua berotzen ari da"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tableta berotzen ari da"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Eginbide batzuk ezingo dira erabili telefonoa hozten den arte.\nInformazio gehiago lortzeko, sakatu hau"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Eginbide batzuk ezingo dira erabili gailua hozten den arte.\nInformazio gehiago lortzeko, sakatu hau"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Eginbide batzuk ezingo dira erabili tableta hozten den arte.\nInformazio gehiago lortzeko, sakatu hau"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefonoa automatikoki saiatuko da hozten. Hoztu bitartean, erabiltzen jarrai dezakezu, baina baliteke mantsoago funtzionatzea.\n\nHozten denean, ohi bezala funtzionatuko du."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Gailua automatikoki saiatuko da hozten. Hoztu bitartean, erabiltzen jarrai dezakezu, baina baliteke mantsoago funtzionatzea.\n\nHozten denean, ohi bezala funtzionatuko du."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tableta automatikoki saiatuko da hozten. Hoztu bitartean, erabiltzen jarrai dezakezu, baina baliteke mantsoago funtzionatzea.\n\nHozten denean, ohi bezala funtzionatuko du."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Hatz-marken sentsorea etengailuan dago. Tabletaren ertzeko bolumen-botoi goratuaren ondoan dagoen botoi laua da."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Hatz-marken sentsorea etengailuan dago. Gailuaren ertzeko bolumen-botoi goratuaren ondoan dagoen botoi laua da."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Hatz-marken sentsorea etengailuan dago. Telefonoaren ertzeko bolumen-botoi goratuaren ondoan dagoen botoi laua da."</string>
diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml
index a861261..30121cc 100644
--- a/packages/SystemUI/res-product/values-fa/strings.xml
+++ b/packages/SystemUI/res-product/values-fa/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. نمایه کاری پاک میشود که با آن همه دادههای نمایه حذف میشود."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که بااستفاده از یک حساب ایمیل قفل رایانه لوحیتان را باز کنید.\n\n لطفاً پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پساز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که بااستفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پساز <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"تلفن بهعلت گرم شدن خاموش شد"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"دستگاه بهعلت گرم شدن خاموش شد"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"رایانه لوحی بهعلت گرم شدن خاموش شد"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"اکنون عملکرد تلفنتان به حالت عادی برگشته است.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"اکنون عملکرد دستگاهتان به حالت عادی برگشته است.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"اکنون عملکرد رایانه لوحیتان به حالت عادی برگشته است.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"تلفنتان خیلی گرم شده بود، بنابراین خاموش شد تا خنک شود. اکنون تلفنتان عملکرد معمولش را دارد.\n\nتلفنتان ممکن است خیلی گرم شود، اگر:\n • از برنامههای نیازمند پردازش زیاد (مثل بازی، ویدیو، یا برنامههای ناوبری) استفاده کنید\n • فایلهای بزرگ بارگیری یا بارگذاری کنید\n • در دماهای بالا از تلفنتان استفاده کنید"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"دستگاهتان خیلی گرم شده بود، بنابراین خاموش شد تا خنک شود. اکنون دستگاهتان عملکرد معمولش را دارد.\n\nدستگاهتان ممکن است خیلی گرم شود، اگر:\n • از برنامههای نیازمند پردازش زیاد (مثل بازی، ویدیو، یا برنامههای ناوبری) استفاده کنید\n • فایلهای بزرگ بارگیری یا بارگذاری کنید\n • در دماهای بالا از دستگاهتان استفاده کنید"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"رایانه لوحیتان خیلی گرم شده بود، بنابراین خاموش شد تا خنک شود. اکنون رایانه لوحیتان عملکرد معمولش را دارد.\n\nرایانه لوحیتان ممکن است خیلی گرم شود، اگر:\n • از برنامههای نیازمند پردازش زیاد (مثل بازی، ویدیو، یا برنامههای ناوبری) استفاده کنید\n • فایلهای بزرگ بارگیری یا بارگذاری کنید\n • در دماهای بالا از رایانه لوحیتان استفاده کنید"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"تلفن درحال گرم شدن است"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"دستگاه درحال گرم شدن است"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"رایانه لوحی درحال گرم شدن است"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"وقتی تلفن درحال خنک شدن است، بعضیاز ویژگیها محدود میشوند.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"وقتی دستگاه درحال خنک شدن است، بعضیاز ویژگیها محدود میشوند.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"وقتی رایانه لوحی درحال خنک شدن است، بعضیاز ویژگیها محدود میشوند.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"تلفنتان بهطور خودکار سعی میکند خنک شود. همچنان میتوانید از تلفنتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی تلفن خنک شد، عملکرد عادیاش از سرگرفته میشود."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"دستگاهتان بهطور خودکار سعی میکند خنک شود. همچنان میتوانید از دستگاهتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی دستگاه خنک شد، عملکرد عادیاش از سرگرفته میشود."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"رایانه لوحیتان بهطور خودکار سعی میکند خنک شود. همچنان میتوانید از رایانه لوحیتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی رایانه لوحی خنک شد، عملکرد عادیاش از سرگرفته میشود."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"حسگر اثر انگشت روی دکمه روشن/خاموش قرار دارد. این همان دکمه مسطحی است که در کنار دکمه برآمده صدا در لبه رایانه لوحی قرار دارد."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"حسگر اثر انگشت روی دکمه روشن/خاموش قرار دارد. این همان دکمه مسطحی است که در کنار دکمه برآمده صدا در لبه دستگاه قرار دارد."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"حسگر اثر انگشت روی دکمه روشن/خاموش قرار دارد. این همان دکمه مسطحی است که در کنار دکمه برآمده صدا در لبه تلفن قرار دارد."</string>
diff --git a/packages/SystemUI/res-product/values-fi/strings.xml b/packages/SystemUI/res-product/values-fi/strings.xml
index c6db4fe..3ed7f6d 100644
--- a/packages/SystemUI/res-product/values-fi/strings.xml
+++ b/packages/SystemUI/res-product/values-fi/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Työprofiili ja kaikki sen data poistetaan."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan tabletin lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään avaamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Puhelin sammui kuumuuden takia"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Laite sammui kuumuuden takia"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tabletti sammui kuumuuden takia"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Puhelimesi toimii nyt normaalisti.\nLue lisää napauttamalla"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Laitteesi toimii nyt normaalisti.\nLue lisää napauttamalla"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tablettisi toimii nyt normaalisti.\nLue lisää napauttamalla"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Puhelimesi oli liian kuuma, joten se sammui. Puhelimesi toimii nyt normaalisti.\n\nPuhelimesi voi kuumentua liikaa, jos\n • käytät paljon resursseja vaativia sovelluksia (esim. pelejä, videoita tai navigointisovelluksia)\n • lataat tai lähetät suuria tiedostoja\n • käytät puhelintasi korkeissa lämpötiloissa."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Laitteesi oli liian kuuma, joten se sammui. Laitteesi toimii nyt normaalisti.\n\nLaitteesi voi kuumentua liikaa, jos\n • käytät paljon resursseja vaativia sovelluksia (esim. pelejä, videoita tai navigointisovelluksia)\n • lataat tai lähetät suuria tiedostoja\n • käytät laitetta korkeissa lämpötiloissa."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablettisi oli liian kuuma, joten se sammui. Tablettisi toimii nyt normaalisti.\n\nTablettisi voi kuumentua liikaa, jos\n • käytät paljon resursseja vaativia sovelluksia (esim. pelejä, videoita tai navigointisovelluksia)\n • lataat tai lähetät suuria tiedostoja\n • käytät tablettia korkeissa lämpötiloissa."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Puhelin lämpenee"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Laite lämpenee"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tabletti lämpenee"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana.\nLue lisää napauttamalla"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Joidenkin ominaisuuksien käyttöä on rajoitettu laitteen jäähtymisen aikana.\nLue lisää napauttamalla"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Joidenkin ominaisuuksien käyttöä on rajoitettu tabletin jäähtymisen aikana.\nLue lisää napauttamalla"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Puhelimesi yrittää automaattisesti jäähdyttää itsensä. Voit silti käyttää puhelinta, mutta se voi toimia hitaammin.\n\nKun puhelin on jäähtynyt, se toimii normaalisti."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Laitteesi yrittää jäähtyä automaattisesti. Voit silti käyttää laitetta, mutta se voi toimia hitaammin.\n\nKun laite on jäähtynyt, se toimii normaalisti."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablettisi yrittää jäähtyä automaattisesti. Voit silti käyttää tablettia, mutta se voi toimia hitaammin.\n\nKun tabletti on jäähtynyt, se toimii normaalisti."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sormenjälkitunnistin on virtapainikkeessa. Se on litteä painike koholla olevan äänenvoimakkuuspainikkeen vieressä tabletin sivussa."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sormenjälkitunnistin on virtapainikkeessa. Se on litteä painike koholla olevan äänenvoimakkuuspainikkeen vieressä laitteen sivussa."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sormenjälkitunnistin on virtapainikkeessa. Se on litteä painike koholla olevan äänenvoimakkuuspainikkeen vieressä puhelimen sivussa."</string>
diff --git a/packages/SystemUI/res-product/values-fr-rCA/strings.xml b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
index 3862796..1b6c6099 100644
--- a/packages/SystemUI/res-product/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-product/values-fr-rCA/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de courriel.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Le téléphone s\'est éteint; surchauffage."</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"L\'appareil s\'est éteint; surchauffage."</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"La tablette s\'est éteinte; surchauffage."</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Votre téléphone fonctionne normalement maintenant.\nTouchez pour en savoir plus"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Votre appareil fonctionne normalement maintenant.\nTouchez pour en savoir plus"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Votre tablette fonctionne normalement maintenant.\nTouchez pour en savoir plus."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Votre téléphone surchauffait et s\'est éteint afin de se refroidir. Il fonctionne normalement maintenant.\n\nIl peut surchauffer si vous :\n • utilisez. des applications qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • si vous l\'utilisez lors de températures élevées."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Votre téléphone surchauffait et s\'est éteint afin de se refroidir. Il fonctionne normalement maintenant.\n\nIl peut surchauffer si vous :\n • utilisez. des applications qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • ou si vous l\'utilisez lors de températures élevées."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Votre tablette surchauffait et s\'est éteinte afin de se refroidir. Elle fonctionne normalement maintenant.\n\nElle peut surchauffer si vous :\n • utilisez. des applications qui utilisent beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • téléchargez ou téléversez des fichiers lourds \n • si vous l\'utilisez lors de températures élevées."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Le téléphone surchauffe"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"L\'appareil surchauffe"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"La tablette surchauffe"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Certaines fonctionnalités sont limitées lors du refroidissement du téléphone.\nTouchez pour en savoir plus"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Certaines fonctionnalités sont limitées lors du refroidissement du téléphone.\nTouchez pour en savoir plus"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Certaines fonctionnalités sont limitées lors du refroidissement du téléphone.\nTouchez pour en savoir plus"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Votre téléphone va se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il va fonctionner normalement."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Votre téléphone va se refroidir automatiquement. Vous pouvez toujours utiliser votre téléphone, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Votre tablette va se refroidir automatiquement. Vous pouvez toujours utiliser votre tablette, mais elle risque d\'être plus lente.\n\nUne fois refroidie, elle va fonctionner normalement."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Le capteur d\'empreintes digitales est situé sur l\'interrupteur. Il s\'agit du bouton plat situé à côté du bouton de volume surélevé, sur le bord de la tablette."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Le capteur d\'empreintes digitales est situé sur l\'interrupteur. Il s\'agit du bouton plat situé à côté du bouton de volume surélevé, sur le bord de l\'appareil."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Le capteur d\'empreintes digitales est situé sur l\'interrupteur. Il s\'agit du bouton plat situé à côté du bouton de volume surélevé, sur le bord du téléphone."</string>
diff --git a/packages/SystemUI/res-product/values-fr/strings.xml b/packages/SystemUI/res-product/values-fr/strings.xml
index d874882..eedc182 100644
--- a/packages/SystemUI/res-product/values-fr/strings.xml
+++ b/packages/SystemUI/res-product/values-fr/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Le profil professionnel et toutes les données associées vont être supprimés."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\nRéessayez dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Téléphone éteint car il surchauffait"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Appareil éteint car il surchauffait"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablette éteinte car elle surchauffait"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"À présent, votre téléphone fonctionne normalement.\nAppuyer pour en savoir plus"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"À présent, votre appareil fonctionne normalement.\nAppuyer pour en savoir plus"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"À présent, votre tablette fonctionne normalement.\nAppuyer pour en savoir plus"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Votre téléphone s\'est éteint, car il surchauffait. Il s\'est refroidi et fonctionne normalement.\n\nIl peut surchauffer si vous :\n • exécutez des applis utilisant beaucoup de ressources (jeux, vidéo, navigation, etc.) ;\n • téléchargez ou importez de gros fichiers ;\n • utilisez votre téléphone à des températures élevées."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Votre appareil s\'est éteint, car il surchauffait. Il s\'est refroidi et fonctionne normalement.\n\nIl peut surchauffer si vous :\n • exécutez des applis utilisant beaucoup de ressources (jeux, vidéo, navigation, etc.) ;\n • téléchargez ou importez de gros fichiers ;\n • utilisez votre appareil à des températures élevées."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Votre tablette s\'est éteinte, car elle surchauffait. Elle s\'est refroidie et fonctionne normalement.\n\nElle peut surchauffer si vous :\n • exécutez des applis utilisant beaucoup de ressources (jeux, vidéo, navigation, etc.) ;\n • téléchargez ou importez de gros fichiers ;\n • utilisez votre tablette à des températures élevées."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Le téléphone chauffe"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"L\'appareil chauffe"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"La tablette chauffe"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Fonctionnalités limitées pendant le refroidissement du téléphone.\nAppuyer pour en savoir plus"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Fonctionnalités limitées pendant le refroidissement de l\'appareil.\nAppuyer pour en savoir plus"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Fonctionnalités limitées pendant le refroidissement de la tablette.\nAppuyer pour en savoir plus"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Votre appareil va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Votre tablette va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais elle risque d\'être plus lente.\n\nUne fois refroidie elle fonctionnera normalement."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Le lecteur d\'empreinte digitale est sur le bouton Marche/Arrêt. C\'est le bouton plat à côté du bouton de volume en relief sur un bord de la tablette."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Le lecteur d\'empreinte digitale est sur le bouton Marche/Arrêt. C\'est le bouton plat à côté du bouton de volume en relief sur un bord de l\'appareil."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Le lecteur d\'empreinte digitale est sur le bouton Marche/Arrêt. C\'est le bouton plat à côté du bouton de volume en relief sur un bord du téléphone."</string>
diff --git a/packages/SystemUI/res-product/values-gl/strings.xml b/packages/SystemUI/res-product/values-gl/strings.xml
index b3e03ca..67be4b2 100644
--- a/packages/SystemUI/res-product/values-gl/strings.xml
+++ b/packages/SystemUI/res-product/values-gl/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Quitarase o perfil de traballo e, por conseguinte, todos os seus datos."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Debuxaches o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear a tableta a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Debuxaches o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"O teléfono apagouse pola calor"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"O dispositivo apagouse pola calor"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"A tableta apagouse pola calor"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"O teléfono funciona con normalidade.\nToca para obter máis información"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"O dispositivo funciona con normalidade.\nToca para obter máis información"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"A tableta funciona con normalidade.\nToca para obter máis información"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Como teléfono estaba demasiado quente, apagouse para arrefriar. Agora funciona con normalidade.\n\nÉ posible que se quente demasiado se:\n • Usas aplicacións que requiran moitos recursos (como aplicacións de navegación, vídeos ou xogos).\n • Descargas ou cargas ficheiros grandes.\n • Utilizas o teléfono en ambientes con temperatura elevada."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Como o dispositivo estaba demasiado quente, apagouse para arrefriar. Agora funciona con normalidade.\n\nÉ posible que se quente demasiado se:\n • Usas aplicacións que requiran moitos recursos (como aplicacións de navegación, vídeos ou xogos).\n • Descargas ou cargas ficheiros grandes.\n • Utilizas o dispositivo en ambientes con temperatura elevada."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Como a tableta estaba demasiado quente, apagouse para arrefriar. Agora funciona con normalidade.\n\nÉ posible que se quente demasiado se:\n • Usas aplicacións que requiran moitos recursos (como aplicacións de navegación, vídeos ou xogos).\n • Descargas ou cargas ficheiros grandes.\n • Utilizas a tableta en ambientes con temperatura elevada."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"O teléfono estase quentando"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"O dispositivo estase quentando"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"A tableta estase quentando"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Algunhas funcións estarán limitadas mentres arrefría o teléfono.\nToca para obter máis información"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Algunhas funcións estarán limitadas mentres arrefría o dispositivo.\nToca para obter máis información"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Algunhas funcións estarán limitadas mentres arrefría a tableta.\nToca para obter máis información"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"O teléfono tentará arrefriar automaticamente. Podes utilizalo igual, pero quizais vaia máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"O dispositivo tentará arrefriar automaticamente. Podes utilizalo igual, pero quizais vaia máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"A tableta tentará arrefriar automaticamente. Podes utilizala igual, pero quizais vaia máis lenta.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impresión dixital está no botón de acendido. É o botón plano que se atopa a carón do botón de volume con relevo, no lateral da tableta."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impresión dixital está no botón de acendido. É o botón plano que se atopa a carón do botón de volume con relevo, no lateral do dispositivo."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impresión dixital está no botón de acendido. É o botón plano que se atopa a carón do botón de volume con relevo, no lateral do teléfono."</string>
diff --git a/packages/SystemUI/res-product/values-gu/strings.xml b/packages/SystemUI/res-product/values-gu/strings.xml
index 4621be3..d43c3d3 100644
--- a/packages/SystemUI/res-product/values-gu/strings.xml
+++ b/packages/SystemUI/res-product/values-gu/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"તમે ફોનને <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે અનલૉક કરવાનો પ્રયાસ કર્યો છે. આ કાર્યાલયની પ્રોફાઇલ કાઢી નાખવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને ડિલીટ કરી દેશે."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટૅબ્લેટને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરી પ્રયાસ કરો."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી છે. વધુ <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસો પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ગરમ થવાના કારણે ફોન બંધ થઇ ગયો છે"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ગરમ થવાના કારણે ડિવાઇસ બંધ થઈ ગયું છે"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ગરમ થવાના કારણે ટૅબ્લેટ બંધ થઈ ગયું છે"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"તમારો ફોન હવે સામાન્ય રીતે કાર્ય કરી રહ્યો છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"તમારું ડિવાઇસ હવે સામાન્ય રીતે કાર્ય કરી રહ્યું છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"તમારું ટૅબ્લેટ હવે સામાન્ય રીતે કાર્ય કરી રહ્યું છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"તમારો ફોન અત્યંત ગરમ હતો, તેથી તે ઠંડો થવા ઑટોમૅટિક રીતે બંધ થઈ ગયો છે. તમારો ફોન હવે સામાન્ય રીતે કાર્ય કરી રહ્યો છે.\n\nતમારો ફોન અત્યંત ગરમ થઈ શકે છે, જો તમે:\n • એવી ઍપ વાપરતા હો જે સંસાધન સઘન રીતે વાપરતી હોય (જેમ કે ગેમિંગ, વીડિયો, અથવા નેવિગેટ કરતી ઍપ)\n • મોટી ફાઇલો અપલોડ અથવા ડાઉનલોડ કરતા હો\n • તમારા ફોનનો ઉપયોગ ઉચ્ચ તાપમાનમાં કરતા હો"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"તમારું ડિવાઇસ અત્યંત ગરમ હતું, તેથી તે ઠંડું થવા ઑટોમૅટિક રીતે બંધ થઈ ગયું છે. તમારું ડિવાઇસ હવે સામાન્ય રીતે કાર્ય કરી રહ્યું છે.\n\nતમારું ડિવાઇસ અત્યંત ગરમ થઈ શકે છે, જો તમે:\n • એવી ઍપ વાપરતા હો જે સંસાધન સઘન રીતે વાપરતી હોય (જેમ કે ગેમિંગ, વીડિયો, અથવા નેવિગેટ કરતી ઍપ)\n • મોટી ફાઇલો અપલોડ અથવા ડાઉનલોડ કરતા હો\n • તમારા ડિવાઇસનો ઉપયોગ ઉચ્ચ તાપમાનમાં કરતા હો"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"તમારું ટૅબ્લેટ અત્યંત ગરમ હતું, તેથી તે ઠંડું થવા ઑટોમૅટિક રીતે બંધ થઈ ગયું છે. તમારું ટૅબ્લેટ હવે સામાન્ય રીતે કાર્ય કરી રહ્યું છે.\n\nતમારું ટૅબ્લેટ અત્યંત ગરમ થઈ શકે છે, જો તમે:\n • એવી ઍપ વાપરતા હો જે સંસાધન સઘન રીતે વાપરતી હોય (જેમ કે ગેમિંગ, વીડિયો, અથવા નેવિગેટ કરતી ઍપ)\n • મોટી ફાઇલો અપલોડ અથવા ડાઉનલોડ કરતા હો\n • તમારા ટૅબ્લેટનો ઉપયોગ ઉચ્ચ તાપમાનમાં કરતા હો"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ફોન ગરમ થવા લાગ્યો છે"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ડિવાઇસ ગરમ થવા લાગ્યું છે"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ટૅબ્લેટ ગરમ થવા લાગ્યું છે"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ફોન ઠંડો થાય ત્યાં સુધી અમુક સુવિધાઓ મર્યાદિત હોય છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ડિવાઇસ ઠંડું થાય ત્યાં સુધી અમુક સુવિધાઓ મર્યાદિત હોય છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ટૅબ્લેટ ઠંડું થાય ત્યાં સુધી અમુક સુવિધાઓ મર્યાદિત હોય છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"તમારો ફોન ઑટોમૅટિક રીતે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nએકવાર તમારો ફોન ઠંડો થઈ ગયા પછી, તે સામાન્ય રીતે ચાલશે."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"તમારું ડિવાઇસ ઑટોમૅટિક રીતે ઠંડુ થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ડિવાઇસનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડું ધીમું કાર્ય કરે.\n\nએકવાર તમારું ડિવાઇસ ઠંડું થઈ ગયા પછી, તે સામાન્ય રીતે કાર્ય કરશે."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"તમારું ટૅબ્લેટ ઑટોમૅટિક રીતે ઠંડું થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ટૅબ્લેટનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડું ધીમું ચાલે.\n\nએકવાર તમારું ટૅબ્લેટ ઠંડું થઈ ગયા પછી, તે સામાન્ય રીતે કાર્ય કરશે."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ફિંગરપ્રિન્ટ સેન્સર પાવર બટન પર છે. તે ટૅબ્લેટની કિનારીએ આવેલા ઉપસેલા વૉલ્યૂમ બટનની બાજુમાં આવેલું સપાટ બટન છે."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ફિંગરપ્રિન્ટ સેન્સર પાવર બટન પર છે. તે ડિવાઇસની કિનારીએ આવેલા ઉપસેલા વૉલ્યૂમ બટનની બાજુમાં આવેલું સપાટ બટન છે."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ફિંગરપ્રિન્ટ સેન્સર પાવર બટન પર છે. તે ફોનની કિનારીએ આવેલા ઉપસેલા વૉલ્યૂમ બટનની બાજુમાં આવેલું સપાટ બટન છે."</string>
diff --git a/packages/SystemUI/res-product/values-hi/strings.xml b/packages/SystemUI/res-product/values-hi/strings.xml
index 4c69df50..dab5f57 100644
--- a/packages/SystemUI/res-product/values-hi/strings.xml
+++ b/packages/SystemUI/res-product/values-hi/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत पासवर्ड डाल चुके हैं. इसकी वजह से वर्क प्रोफ़ाइल को हटा दिया जाएगा जिससे उपयोगकर्ता की प्रोफ़ाइल का सारा डेटा मिट जाएगा."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"आपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. इसलिए, <xliff:g id="NUMBER_1">%2$d</xliff:g> और गलत पैटर्न बनाने के बाद, टैबलेट को अनलॉक करने के लिए आपसे ईमेल खाते का इस्तेमाल करने को कहा जाएगा.\n\n अनलॉक करने के लिए <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"आपने लॉक खोलने के पैटर्न को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से बनाया है. इसलिए, <xliff:g id="NUMBER_1">%2$d</xliff:g> और गलत पैटर्न बनाने के बाद, आपसे फ़ोन को अनलॉक करने के लिए ईमेल खाते का इस्तेमाल करने को कहा जाएगा.\n\n अनलॉक करने के लिए <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से कोशिश करें."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"गर्म होने की वजह से फ़ोन बंद हो गया"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"गर्म होने की वजह से डिवाइस बंद हो गया"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"गर्म होने की वजह से टैबलेट बंद हो गया"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"आपका फ़ोन अब सामान्य रूप से काम कर रहा है.\nज़्यादा जानकारी के लिए टैप करें"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"आपका डिवाइस अब सामान्य रूप से काम कर रहा है.\nज़्यादा जानकारी के लिए टैप करें"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"आपका टैबलेट अब सामान्य रूप से काम कर रहा है.\nज़्यादा जानकारी के लिए टैप करें"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"आपका फ़ोन बहुत गर्म हो गया था. इसलिए, यह ठंडा होने के लिए बंद हो गया. फ़ोन अब सामान्य रूप से काम कर रहा है.\n\nफ़ोन बहुत गर्म हो सकता है, अगर:\n • ज़्यादा रिसॉर्स का इस्तेमाल करने वाले ऐप्लिकेशन चलाए जाते हैं. जैसे, गेमिंग, वीडियो या नेविगेशन ऐप्लिकेशन\n • बड़ी फ़ाइलें डाउनलोड या अपलोड की जाती हैं\n • ज़्यादा तापमान में फ़ोन का इस्तेमाल किया जाता है"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"आपका डिवाइस बहुत गर्म हो गया था. इसलिए, यह ठंडा होने के लिए बंद हो गया. डिवाइस अब सामान्य रूप से काम कर रहा है.\n\nडिवाइस बहुत गर्म हो सकता है, अगर:\n • ज़्यादा रिसॉर्स का इस्तेमाल करने वाले ऐप्लिकेशन चलाए जाते हैं. जैसे, गेमिंग, वीडियो या नेविगेशन ऐप्लिकेशन\n • बड़ी फ़ाइलें डाउनलोड या अपलोड की जाती हैं\n • ज़्यादा तापमान में डिवाइस का इस्तेमाल किया जाता है"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"आपका टैबलेट बहुत गर्म हो गया था. इसलिए, यह ठंडा होने के लिए बंद हो गया. टैबलेट अब सामान्य रूप से काम कर रहा है.\n\nटैबलेट बहुत गर्म हो सकता है, अगर:\n • ज़्यादा रिसॉर्स का इस्तेमाल करने वाले ऐप्लिकेशन चलाए जाते हैं. जैसे, गेमिंग, वीडियो या नेविगेशन ऐप्लिकेशन\n • बड़ी फ़ाइलें डाउनलोड या अपलोड की जाती हैं\n • ज़्यादा तापमान में टैबलेट का इस्तेमाल किया जाता है"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"फ़ोन गर्म हो रहा है"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"डिवाइस गर्म हो रहा है"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"टैबलेट गर्म हो रहा है"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"फ़ोन के ठंडा होने तक कुछ सुविधाएं काम नहीं करतीं.\nज़्यादा जानकारी के लिए टैप करें"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"डिवाइस के ठंडा होने तक कुछ सुविधाएं काम नहीं करतीं.\nज़्यादा जानकारी के लिए टैप करें"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"टैबलेट के ठंडा होने तक कुछ सुविधाएं काम नहीं करतीं.\nज़्यादा जानकारी के लिए टैप करें"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"आपका फ़ोन अपने-आप ठंडा हो जाएगा. इस दौरान भी अपने फ़ोन का इस्तेमाल किया जा सकता है. हालांकि, ऐसे में फ़ोन शायद धीमा काम करे.\n\nठंडा हो जाने के बाद, यह पहले की तरह काम करेगा."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"आपका डिवाइस अपने-आप ठंडा हो जाएगा. इस दौरान भी अपने डिवाइस का इस्तेमाल किया जा सकता है. हालांकि, ऐसे में डिवाइस शायद धीमा काम करे.\n\nठंडा हो जाने के बाद, यह पहले की तरह काम करेगा."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"आपका टैबलेट अपने-आप ठंडा हो जाएगा. इस दौरान भी अपने टैबलेट का इस्तेमाल किया जा सकता है. हालांकि, ऐसे में टैबलेट शायद धीमा काम करे.\n\nठंडा हो जाने के बाद, यह पहले की तरह काम करेगा."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"फ़िंगरप्रिंट सेंसर, पावर बटन पर होता है. यह टैबलेट के किनारे पर मौजूद एक फ़्लैट बटन होता है, जो कि आपको आवाज़ कम या ज़्यादा करने वाले उभरे हुए बटन के बगल में मिलेगा."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"फ़िंगरप्रिंट सेंसर, पावर बटन पर होता है. यह डिवाइस के किनारे पर मौजूद एक फ़्लैट बटन होता है, जो कि आपको आवाज़ कम या ज़्यादा करने वाले उभरे हुए बटन के बगल में मिलेगा."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"फ़िंगरप्रिंट सेंसर, पावर बटन पर होता है. यह फ़ोन के किनारे पर मौजूद एक फ़्लैट बटन होता है, जो कि आपको आवाज़ कम या ज़्यादा करने वाले उभरे हुए बटन के बगल में मिलेगा."</string>
diff --git a/packages/SystemUI/res-product/values-hr/strings.xml b/packages/SystemUI/res-product/values-hr/strings.xml
index a7bd4b0..8be9a22 100644
--- a/packages/SystemUI/res-product/values-hr/strings.xml
+++ b/packages/SystemUI/res-product/values-hr/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Neuspješno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> put/a. Radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati tablet pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> put/a. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon se isključio zbog vrućine"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Uređaj se isključio zbog vrućine"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet se isključio zbog vrućine"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefon sad radi normalno.\nDodirnite za više informacija."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Uređaj sad radi normalno.\nDodirnite za više informacija."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tablet sad radi normalno.\nDodirnite za više informacija."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon se pregrijao, stoga se isključio kako bi se ohladio Telefon sada radi normalno.\n\nTelefon se može pregrijati ako:\n • Upotrebljavate zahtjevne aplikacije (kao što su igre, aplikacije za videozapise ili navigaciju).\n • Preuzimate ili prenosite velike datoteke.\n • Upotrebljavate telefon na visokim temperaturama."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Uređaj se pregrijao, stoga se isključio kako bi se ohladio Uređaj sada radi normalno.\n\nUređaj se može pregrijati ako:\n • Upotrebljavate zahtjevne aplikacije (kao što su igre, aplikacije za videozapise ili navigaciju).\n • Preuzimate ili prenosite velike datoteke.\n • Upotrebljavate uređaj na visokim temperaturama."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablet se pregrijao, stoga se isključio kako bi se ohladio Tablet sada radi normalno.\n\nTablet se može pregrijati ako:\n • Upotrebljavate zahtjevne aplikacije (kao što su igre, aplikacije za videozapise ili navigaciju).\n • Preuzimate ili prenosite velike datoteke.\n • Upotrebljavate tablet na visokim temperaturama."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon se zagrijava"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Uređaj se zagrijava"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet se zagrijava"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Neke su značajke ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Neke su značajke ograničene dok se uređaj ne ohladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Neke su značajke ograničene dok se tablet ne ohladi.\nDodirnite za više informacija"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefon će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Uređaj će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablet će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor otiska prsta nalazi se na tipki za uključivanje/isključivanje. To je ravni gumb pored izdignutog gumba za glasnoću na rubu tableta."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor otiska prsta nalazi se na tipki za uključivanje/isključivanje. To je ravni gumb pored izdignutog gumba za glasnoću na rubu uređaja."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor otiska prsta nalazi se na tipki za uključivanje/isključivanje. To je ravni gumb pored izdignutog gumba za glasnoću na rubu telefona."</string>
diff --git a/packages/SystemUI/res-product/values-hu/strings.xml b/packages/SystemUI/res-product/values-hu/strings.xml
index 75c10e9..34f20a0 100644
--- a/packages/SystemUI/res-product/values-hu/strings.xml
+++ b/packages/SystemUI/res-product/values-hu/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. A rendszer eltávolítja a munkaprofilt, és ezzel a profil összes adata törlődik."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania táblagépét.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után e-mail-fiók használatával kell feloldania telefonját.\n\nPróbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"A telefon a meleg miatt kikapcsolt"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Az eszköz a meleg miatt kikapcsolt"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"A táblagép a meleg miatt kikapcsolt"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefonja most már megfelelően működik.\nKoppintson, ha további információra van szüksége."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Eszköze most már megfelelően működik.\nKoppintson, ha további információra van szüksége."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Táblagépe most már megfelelően működik.\nKoppintson, ha további információra van szüksége."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefonja túlmelegedett, így kikapcsolt, hogy lehűlhessen. Most már megfelelően működik.\n\nA telefon akkor melegedhet túl, ha Ön:\n • Energiaigényes alkalmazásokat használ (például játékokat, videókat vagy navigációs alkalmazásokat)\n • Nagy fájlokat tölt le vagy fel\n • Melegben használja a telefonját"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Eszköze túlmelegedett, így kikapcsolt, hogy lehűlhessen. Most már megfelelően működik.\n\nAz eszköz akkor melegedhet túl, ha Ön:\n • Energiaigényes alkalmazásokat használ (például játékokat, videókat vagy navigációs alkalmazásokat)\n • Nagy fájlokat tölt le vagy fel\n • Melegben használja eszközét"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Táblagépe túlmelegedett, így kikapcsolt, hogy lehűlhessen. Most már megfelelően működik.\n\nA táblagép akkor melegedhet túl, ha Ön:\n • Energiaigényes alkalmazásokat használ (például játékokat, videókat vagy navigációs alkalmazásokat)\n • Nagy fájlokat tölt le vagy fel\n • Melegben használja a táblagépet"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"A telefon melegszik"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Az eszköz melegszik"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"A táblagép melegszik"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Bizonyos funkciók korlátozottan működnek a telefon lehűlése közben.\nKoppintson, ha további információra van szüksége."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Bizonyos funkciók korlátozottan működnek az eszköz lehűlése közben.\nKoppintson, ha további információra van szüksége."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Bizonyos funkciók korlátozottan működnek a táblagép lehűlése közben.\nKoppintson, ha további információra van szüksége."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"A telefon automatikusan megpróbál lehűlni. Továbbra is tudja használni a telefont, de elképzelhető, hogy működése lelassul.\n\nAmint a telefon lehűl, újra a szokásos módon működik majd."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Az eszköz automatikusan megpróbál lehűlni. Továbbra is tudja használni, de elképzelhető, hogy működése lelassul.\n\nAmint az eszköz lehűl, újra a szokásos módon működik majd."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"A táblagép automatikusan megpróbál lehűlni. Továbbra is tudja használni, de elképzelhető, hogy működése lelassul.\n\nAmint a táblagép lehűl, újra a szokásos módon működik majd."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Az ujjlenyomat-érzékelő a bekapcsológombon található. Ez a kiemelkedő hangerőgomb melletti lapos gomb a táblagép szélén."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Az ujjlenyomat-érzékelő a bekapcsológombon található. Ez a kiemelkedő hangerőgomb melletti lapos gomb az eszköz szélén."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Az ujjlenyomat-érzékelő a bekapcsológombon található. Ez a kiemelkedő hangerőgomb melletti lapos gomb a telefon szélén."</string>
diff --git a/packages/SystemUI/res-product/values-hy/strings.xml b/packages/SystemUI/res-product/values-hy/strings.xml
index acee335..f527eab 100644
--- a/packages/SystemUI/res-product/values-hy/strings.xml
+++ b/packages/SystemUI/res-product/values-hy/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի, և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Դուք կատարել եք ապակողպման նախշը մուտքագրելու <xliff:g id="NUMBER_0">%1$d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել պլանշետը էլփոստի հաշվի միջոցով։\n\n Խնդրում ենք կրկին փորձել <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Դուք <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: Եվս <xliff:g id="NUMBER_1">%2$d</xliff:g> անհաջող փորձից հետո ձեզ կառաջարկվի ապակողպել հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Կրկին փորձեք <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Հեռախոսն անջատվել էր տաքանալու պատճառով"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Սարքն անջատվել էր տաքանալու պատճառով"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Պլանշետն անջատվել էր տաքանալու պատճառով"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Ձեր հեռախոսն այժմ նորմալ է աշխատում։\nՀպեք՝ ավելին իմանալու համար"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Ձեր սարքն այժմ նորմալ է աշխատում։\nՀպեք՝ ավելին իմանալու համար"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Ձեր պլանշետն այժմ նորմալ է աշխատում։\nՀպեք՝ ավելին իմանալու համար"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Ձեր հեռախոսը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար։ Հեռախոսն այժմ նորմալ աշխատում է։\n\nՀեռախոսը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավիգացիայի հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր հեռախոսը բարձր ջերմային պայմաններում"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Ձեր սարքը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար։ Սարքն այժմ նորմալ աշխատում է։\n\nՍարքը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավիգացիայի հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր սարքը բարձր ջերմային պայմաններում"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Ձեր պլանշետը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար: Պլանշետը այժմ նորմալ աշխատում է:\n\nՊլանշետը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավիգացիայի հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր պլանշետը բարձր ջերմային պայմաններում"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Հեռախոսը տաքանում է"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Սարքը տաքանում է"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Պլանշետը տաքանում է"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակված են։\nՀպեք՝ ավելին իմանալու համար"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Հովանալու ընթացքում սարքի որոշ գործառույթներ սահմանափակված են։\nՀպեք՝ ավելին իմանալու համար"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Հովանալու ընթացքում պլանշետի որոշ գործառույթներ սահմանափակված են։\nՀպեք՝ ավելին իմանալու համար"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ։ Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի։\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով։"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Ձեր սարքը ավտոմատ կերպով կփորձի hովանալ։ Կարող եք շարունակել օգտագործել սարքը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո սարքը կաշխատի կանոնավոր կերպով։"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Ձեր պլանշետը ավտոմատ կերպով կփորձի hովանալ։ Կարող եք շարունակել օգտագործել պլանշետը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո պլանշետը կաշխատի կանոնավոր կերպով։"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Մատնահետքերի սկաները սնուցման կոճակի վրա է։ Այն հարթ կոճակ է ձայնի ուժգնության ուռուցիկ կոճակի կողքին՝ պլանշետի կողային մասում։"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Մատնահետքերի սկաները սնուցման կոճակի վրա է։ Այն հարթ կոճակ է ձայնի ուժգնության ուռուցիկ կոճակի կողքին՝ սարքի կողային մասում։"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Մատնահետքերի սկաները սնուցման կոճակի վրա է։ Այն հարթ կոճակ է ձայնի ուժգնության ուռուցիկ կոճակի կողքին՝ հեռախոսի կողային մասում։"</string>
diff --git a/packages/SystemUI/res-product/values-in/strings.xml b/packages/SystemUI/res-product/values-in/strings.xml
index af1895c..2224810 100644
--- a/packages/SystemUI/res-product/values-in/strings.xml
+++ b/packages/SystemUI/res-product/values-in/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Ponsel dimatikan karena panas"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Perangkat dimatikan karena panas"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet dimatikan karena panas"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Ponsel kini berfungsi normal.\nKetuk untuk info selengkapnya"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Perangkat kini berfungsi normal.\nKetuk untuk info selengkapnya"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tablet kini berfungsi normal.\nKetuk untuk info selengkapnya"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Ponsel terlalu panas, jadi dimatikan agar mendingin. Ponsel kini berfungsi normal.\n\nPonsel dapat menjadi terlalu panas jika Anda:\n • Menggunakan aplikasi yang menggunakan sumber daya secara intensif (seperti aplikasi game, video, atau navigasi)\n • Mendownload atau mengupload file besar\n • Menggunakan ponsel dalam suhu tinggi"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Perangkat terlalu panas, jadi dimatikan agar mendingin. Perangkat kini berfungsi normal.\n\nPerangkat dapat menjadi terlalu panas jika Anda:\n • Menggunakan aplikasi yang menggunakan sumber daya secara intensif (seperti aplikasi game, video, atau navigasi)\n • Mendownload atau mengupload file besar\n • Menggunakan perangkat dalam suhu tinggi"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablet terlalu panas, jadi dimatikan agar mendingin. Tablet kini berfungsi normal.\n\nTablet dapat menjadi terlalu panas jika Anda:\n • Menggunakan aplikasi yang menggunakan sumber daya secara intensif (seperti aplikasi game, video, atau navigasi)\n • Mendownload atau mengupload file besar\n • Menggunakan tablet dalam suhu tinggi"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Ponsel menjadi panas"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Perangkat menjadi panas"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet menjadi panas"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Beberapa fitur dibatasi saat ponsel mendingin.\nKetuk untuk info selengkapnya"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Beberapa fitur dibatasi saat perangkat mendingin.\nKetuk untuk info selengkapnya"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Beberapa fitur dibatasi saat tablet mendingin.\nKetuk untuk info selengkapnya"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Ponsel akan otomatis mencoba mendingin. Anda tetap dapat menggunakan ponsel, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, ponsel akan berjalan seperti biasa."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Perangkat akan otomatis mencoba mendingin. Anda tetap dapat menggunakan perangkat, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, perangkat akan berjalan seperti biasa."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablet akan otomatis mencoba mendingin. Anda tetap dapat menggunakan tablet, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, tablet akan berjalan seperti biasa."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sensor sidik jari ada di tombol daya. Tombol ini berupa tombol datar di samping tombol volume timbul di tepi tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sensor sidik jari ada di tombol daya. Tombol ini berupa tombol datar di samping tombol volume timbul di tepi perangkat."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sensor sidik jari ada di tombol daya. Tombol ini berupa tombol datar di samping tombol volume timbul di tepi ponsel."</string>
diff --git a/packages/SystemUI/res-product/values-is/strings.xml b/packages/SystemUI/res-product/values-is/strings.xml
index 1e42255..0f3f71c 100644
--- a/packages/SystemUI/res-product/values-is/strings.xml
+++ b/packages/SystemUI/res-product/values-is/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Vinnusniðið verður fjarlægt, með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna spjaldtölvuna með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verðurðu beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Slökkt var á símanum vegna hita"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Slökkt var á tækinu vegna hita"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Slökkt var á spjaldtölvunni vegna hita"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Síminn virkar nú eins og venjulega.\nÝttu til að fá frekari upplýsingar"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Tækið virkar nú eins og venjulega.\nÝttu til að fá frekari upplýsingar"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Spjaldtölvan virkar nú eins og venjulega.\nÝttu til að fá frekari upplýsingar"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Síminn varð of heitur og því var slökkt á honum til að kæla hann. Síminn virkar núna sem skyldi.\n\nSíminn getur orðið of heitur ef þú:\n • Notar plássfrek forrit (t.d. leikja-, myndbands- eða leiðsagnarforrit\n • Sækir eða hleður upp stórum skrám\n • Notar símann í miklum hita"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Tækið varð of heitt og því var slökkt á því til að kæla það. Tækið virkar núna sem skyldi.\n\nTækið getur orðið of heitt ef þú:\n • Notar plássfrek forrit (t.d. leikja-, myndbands- eða leiðsagnarforrit\n • Sækir eða hleður upp stórum skrám\n • Notar tækið í miklum hita"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Spjaldtölvan varð of heit og því var slökkt á henni til að kæla hana. Spjaldtölvan virkar núna sem skyldi.\n\nSpjaldtölvan getur orðið of heit ef þú:\n • Notar plássfrek forrit (t.d. leikja-, myndbands- eða leiðsagnarforrit\n • Sækir eða hleður upp stórum skrám\n • Notar spjaldtölvuna í miklum hita"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Síminn er að hitna"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Tækið er að hitna"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Spjaldtölvan er að hitna"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Sumir eiginleikar eru takmarkaðir á meðan síminn kælir sig.\nÝttu til að fá frekari upplýsingar"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Sumir eiginleikar eru takmarkaðir á meðan tækið kælir sig.\nÝttu til að fá frekari upplýsingar"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Sumir eiginleikar eru takmarkaðir á meðan spjaldtölvan kælir sig.\nÝttu til að fá frekari upplýsingar"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Síminn reynir að kæla sig sjálfkrafa. Þú getur áfram notað símann en hann gæti verið hægvirkari.\n\nÞegar síminn hefur kælt sig mun hann virka eðlilega."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Tækið reynir að kæla sig sjálfkrafa. Þú getur áfram notað tækið en það gæti verið hægvirkara.\n\nÞegar tækið hefur kælt sig mun það virka eðlilega."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Spjaldtölvan reynir að kæla sig sjálfkrafa. Þú getur áfram notað spjaldtölvuna en hún gæti verið hægvirkari.\n\nÞegar spjaldtölvan hefur kælt sig mun hún virka eðlilega."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingrafaralesarinn er á aflrofanum. Það er flati hnappurinn við hliðina á upphleypta hljóðstyrkshnappnum á hlið spjaldtölvunnar."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingrafaralesarinn er á aflrofanum. Það er flati hnappurinn við hliðina á upphleypta hljóðstyrkshnappnum á hlið tækisins."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingrafaralesarinn er á aflrofanum. Það er flati hnappurinn við hliðina á upphleypta hljóðstyrkshnappnum á hlið símans."</string>
diff --git a/packages/SystemUI/res-product/values-it/strings.xml b/packages/SystemUI/res-product/values-it/strings.xml
index 0b3bb3d..a9fd80b 100644
--- a/packages/SystemUI/res-product/values-it/strings.xml
+++ b/packages/SystemUI/res-product/values-it/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Lo smartphone si è spento per il calore"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Il dispositivo si è spento per il calore"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Il tablet si è spento per il calore"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Ora lo smartphone funziona normalmente.\nTocca per maggiori informazioni"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Ora il dispositivo funziona normalmente.\nTocca per maggiori informazioni"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Ora il tablet funziona normalmente.\nTocca per maggiori informazioni"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Lo smartphone era surriscaldato e si è spento per raffreddarsi. Ora funziona normalmente.\n\nLo smartphone può surriscaldarsi se:\n • Utilizzi app che consumano molte risorse (ad esempio app di navigazione, giochi o video)\n • Scarichi o carichi grandi file\n • Lo utilizzi in presenza di alte temperature"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Il dispositivo era surriscaldato e si è spento per raffreddarsi. Ora funziona normalmente.\n\nIl dispositivo può surriscaldarsi se:\n • Utilizzi app che consumano molte risorse (ad esempio app di navigazione, giochi o video)\n • Scarichi o carichi grandi file\n • Lo utilizzi in presenza di alte temperature"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Il tablet era surriscaldato e si è spento per raffreddarsi. Ora funziona normalmente.\n\nIl tablet può surriscaldarsi se:\n • Utilizzi app che consumano molte risorse (ad esempio app di navigazione, giochi o video)\n • Scarichi o carichi grandi file\n • Lo utilizzi in presenza di alte temperature"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Surriscaldamento smartphone"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Surriscaldamento dispositivo"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Surriscaldamento tablet"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Alcune funzionalità sono state limitate durante il raffreddamento dello smartphone.\nTocca per maggiori informazioni"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Alcune funzionalità sono state limitate durante il raffreddamento del dispositivo.\nTocca per maggiori informazioni"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Alcune funzionalità sono state limitate durante il raffreddamento del tablet.\nTocca per maggiori informazioni"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Lo smartphone cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, lo smartphone funzionerà normalmente."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Il dispositivo cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il dispositivo funzionerà normalmente."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Il tablet cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il tablet funzionerà normalmente."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Il sensore di impronte digitali si trova sul tasto di accensione. Si tratta del tasto piatto accanto al tasto del volume in rilievo sul bordo del tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Il sensore di impronte digitali si trova sul tasto di accensione. Si tratta del tasto piatto accanto al tasto del volume in rilievo sulla parte laterale del dispositivo."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Il sensore di impronte digitali si trova sul tasto di accensione. Si tratta del tasto piatto accanto al tasto del volume in rilievo sulla parte laterale dello smartphone."</string>
diff --git a/packages/SystemUI/res-product/values-iw/strings.xml b/packages/SystemUI/res-product/values-iw/strings.xml
index 71779f30..9365dd9 100644
--- a/packages/SystemUI/res-product/values-iw/strings.xml
+++ b/packages/SystemUI/res-product/values-iw/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים. פרופיל העבודה יוסר וכל נתוני הפרופיל יימחקו."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, ,תישלח אליך בקשה לבטל את נעילת הטאבלט באמצעות חשבון אימייל.\n\n יש לנסות שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"שרטטת קו ביטול נעילה שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תישלח אליך בקשה לבטל את נעילת הטלפון באמצעות חשבון אימייל.\n\n יש לנסות שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"הטלפון כבה בגלל התחממות"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"המכשיר כבה בגלל התחממות"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"הטאבלט כבה בגלל התחממות"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"הטלפון פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"המכשיר פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"הטאבלט פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"הטלפון שלך התחמם יותר מדי וכבה כדי להתקרר. הטלפון פועל כרגיל עכשיו.\n\nייתכן שהטלפון יתחמם יותר מדי אם:\n • משתמשים באפליקציות עתירות משאבים (כמו משחקים, אפליקציות וידאו או אפליקציות ניווט).\n • מורידים או מעלים קבצים גדולים.\n • משתמשים בטלפון בסביבה עם טמפרטורות גבוהות."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"המכשיר שלך התחמם יותר מדי וכבה כדי להתקרר. המכשיר פועל כרגיל עכשיו.\n\nייתכן שהמכשיר יתחמם יותר מדי אם:\n • משתמשים באפליקציות עתירות משאבים (כמו משחקים, אפליקציות וידאו או אפליקציות ניווט).\n • מורידים או מעלים קבצים גדולים.\n • משתמשים במכשיר בסביבה עם טמפרטורות גבוהות."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"הטאבלט שלך התחמם יותר מדי וכבה כדי להתקרר. הטאבלט פועל כרגיל עכשיו.\n\nייתכן שהטאבלט יתחמם יותר מדי אם:\n • משתמשים באפליקציות עתירות משאבים (כמו משחקים, אפליקציות וידאו או אפליקציות ניווט).\n • מורידים או מעלים קבצים גדולים.\n • משתמשים בטאבלט בסביבה עם טמפרטורות גבוהות."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"הטלפון מתחמם"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"המכשיר מתחמם"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"הטאבלט מתחמם"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"חלק מהתכונות מוגבלות כל עוד המכשיר מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"חלק מהתכונות מוגבלות כל עוד הטאבלט מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"קירור הטלפון ייעשה באופן אוטומטי. אפשר עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"קירור המכשיר ייעשה באופן אוטומטי. אפשר עדיין להשתמש במכשיר אבל ייתכן שהוא יפעל לאט יותר.\n\nהמכשיר יחזור לפעול כרגיל לאחר שיתקרר."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"קירור הטאבלט ייעשה באופן אוטומטי. אפשר עדיין להשתמש בטאבלט אבל ייתכן שהוא יפעל לאט יותר.\n\nהטאבלט יחזור לפעול כרגיל לאחר שיתקרר."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בשולי הטאבלט."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בשולי המכשיר."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"חיישן טביעות האצבע נמצא על לחצן ההפעלה. זה הלחצן השטוח ליד הלחצן הבולט של עוצמת הקול בשולי הטלפון."</string>
diff --git a/packages/SystemUI/res-product/values-ja/strings.xml b/packages/SystemUI/res-product/values-ja/strings.xml
index 68f030b..1fc8775 100644
--- a/packages/SystemUI/res-product/values-ja/strings.xml
+++ b/packages/SystemUI/res-product/values-ja/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"スマートフォンのロック解除に <xliff:g id="NUMBER">%d</xliff:g> 回失敗しました。仕事用プロファイルは削除され、プロファイルのデータはすべて消去されます。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、タブレットのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ロック解除パターンの入力を <xliff:g id="NUMBER_0">%1$d</xliff:g> 回間違えました。あと <xliff:g id="NUMBER_1">%2$d</xliff:g> 回間違えると、スマートフォンのロック解除にメール アカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後にもう一度お試しください。"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"温度上昇により電源が OFF になりました"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"温度上昇により電源が OFF になりました"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"温度上昇により電源が OFF になりました"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"お使いのスマートフォンは現在、正常に動作しています。\nタップして詳細を表示"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"お使いのデバイスは現在、正常に動作しています。\nタップして詳細を表示"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"お使いのタブレットは現在、正常に動作しています。\nタップして詳細を表示"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"スマートフォンが熱くなりすぎたため電源が OFF になりました。現在は正常に動作しています。\n\nスマートフォンは以下の場合に熱くなる場合があります。\n • リソースを集中的に使用する機能やアプリ(ゲームアプリ、動画アプリ、ナビアプリなど)を使用\n • サイズの大きいファイルをダウンロードまたはアップロード\n • 高温の場所で使用"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"デバイスが熱くなりすぎたため電源が OFF になりました。現在は正常に動作しています。\n\nデバイスは以下の場合に熱くなる場合があります。\n • リソースを集中的に使用する機能やアプリ(ゲームアプリ、動画アプリ、ナビアプリなど)を使用\n • サイズの大きいファイルをダウンロードまたはアップロード\n • 高温の場所で使用"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"タブレットが熱くなりすぎたため電源が OFF になりました。現在は正常に動作しています。\n\nタブレットは以下の場合に熱くなる場合があります。\n • リソースを集中的に使用する機能やアプリ(ゲームアプリ、動画アプリ、ナビアプリなど)を使用\n • サイズの大きいファイルをダウンロードまたはアップロード\n • 高温の場所で使用"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"スマートフォンの温度が上昇中"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"デバイスの温度が上昇中"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"タブレットの温度が上昇中"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"スマートフォンのクールダウン中は一部の機能が制限されます。\nタップして詳細を表示"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"デバイスのクールダウン中は一部の機能が制限されます。\nタップして詳細を表示"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"タブレットのクールダウン中は一部の機能が制限されます。\nタップして詳細を表示"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"スマートフォンは自動的にクールダウンを行います。その間もスマートフォンを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"デバイスは自動的にクールダウンを行います。その間もデバイスを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"タブレットは自動的にクールダウンを行います。その間もタブレットを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指紋認証センサーは電源ボタンに内蔵されています。タブレット側面のボタンのうち、音量ボタンの横にあるフラットなボタンです。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指紋認証センサーは電源ボタンに内蔵されています。デバイス側面のボタンのうち、音量ボタンの横にあるフラットなボタンです。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指紋認証センサーは電源ボタンに内蔵されています。スマートフォン側面のボタンのうち、音量ボタンの横にあるフラットなボタンです。"</string>
diff --git a/packages/SystemUI/res-product/values-ka/strings.xml b/packages/SystemUI/res-product/values-ka/strings.xml
index 34fc24c..f007c4a 100644
--- a/packages/SystemUI/res-product/values-ka/strings.xml
+++ b/packages/SystemUI/res-product/values-ka/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"თქვენ არასწორად ცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g>-ჯერ. ამის გამო, სამსახურის პროფილი ამოიშლება, რაც პროფილის ყველა მონაცემის წაშლას გამოიწვევს."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ მოგთხოვთ, ტაბლეტი თქვენი ელფოსტის ანგარიშის მეშვეობით განბლოკოთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი მცდელობის შემდეგ მოგთხოვთ, ტელეფონი თქვენი ელფოსტის ანგარიშის მეშვეობით განბლოკოთ.\n\n ცადეთ ხელახლა <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ტელეფონი გამოირთო გაცხელების გამო"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"მოწყობილობა გამოირთო გაცხელების გამო"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ტაბლეტი გამოირთო გაცხელების გამო"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"თქვენი ტელეფონი უკვე ნორმალურად მუშაობს.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"თქვენი მოწყობილობა უკვე ნორმალურად მუშაობს.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"თქვენი ტაბლეტი უკვე ნორმალურად მუშაობს.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"თქვენი ტელეფონი გამოირთო გასაგრილებლად, რადგან ის მეტისმეტად გაცხელდა. ახლა ის ჩვეულებრივად მუშაობს.\n\nტელეფონის გაცხელების მიზეზებია:\n • რესურსტევადი აპების გამოყენება (მაგ.: სათამაშო, ვიდეო ან ნავიგაციის აპების)\n • დიდი ფაილების ჩამოტვირთვა ან ატვირთვა\n • მოწყობილობის გამოყენება მაღალი ტემპერატურისას"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"თქვენი მოწყობილობა გამოირთო გასაგრილებლად, რადგან ის მეტისმეტად გაცხელდა. ახლა ის ჩვეულებრივად მუშაობს.\n\nმოწყობილობის გაცხელების მიზეზებია:\n • რესურსტევადი აპების გამოყენება (მაგ.: სათამაშო, ვიდეო ან ნავიგაციის აპების)\n • დიდი ფაილების ჩამოტვირთვა ან ატვირთვა\n • მოწყობილობის გამოყენება მაღალი ტემპერატურისას"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"თქვენი ტაბლეტი გამოირთო გასაგრილებლად, რადგან ის მეტისმეტად გაცხელდა. ახლა ის ჩვეულებრივად მუშაობს.\n\nტაბლეტის გაცხელების მიზეზებია:\n • რესურსტევადი აპების გამოყენება (მაგ.: სათამაშო, ვიდეო ან ნავიგაციის აპების)\n • დიდი ფაილების ჩამოტვირთვა ან ატვირთვა\n • მოწყობილობის გამოყენება მაღალი ტემპერატურისას"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ტელეფონი ცხელდება"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"მოწყობილობა ცხელდება"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ტაბლეტი ცხელდება"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ მოწყობილობა გაგრილდება.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტაბლეტი გაგრილდება.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"თქვენი ტელეფონი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"თქვენი მოწყობილობა გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"თქვენი ტაბლეტი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ თქვენი ტაბლეტით სარგებლობა, თუმცა მან შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"თითის ანაბეჭდის სენსორი ჩართვის ღილაკზეა. ეს არის ბრტყელი ღილაკი ხმის აწევის ღილაკის გვერდით, ტაბლეტის კიდეში."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"თითის ანაბეჭდის სენსორი ჩართვის ღილაკზეა. ეს არის ბრტყელი ღილაკი ხმის აწევის ღილაკის გვერდით, მოწყობილობის კიდეში."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"თითის ანაბეჭდის სენსორი ჩართვის ღილაკზეა. ეს არის ბრტყელი ღილაკი ხმის აწევის ღილაკის გვერდით, ტელეფონის კიდეში."</string>
diff --git a/packages/SystemUI/res-product/values-kk/strings.xml b/packages/SystemUI/res-product/values-kk/strings.xml
index 73b637e..83b2351 100644
--- a/packages/SystemUI/res-product/values-kk/strings.xml
+++ b/packages/SystemUI/res-product/values-kk/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефон құлпын ашуға <xliff:g id="NUMBER">%d</xliff:g> рет сәтсіз әрекет жасалды. Жұмыс профилі өшіріліп, оның бүкіл деректері жойылады."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін планшетті аккаунт арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Құлыпты ашу өрнегі <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате енгізілді. <xliff:g id="NUMBER_1">%2$d</xliff:g> әрекет қалды. Одан кейін телефонды аккаунт арқылы ашу сұралады. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Телефон қызып кеткендіктен өшірілді"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Құрылғы қызып кеткендіктен өшірілді"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Планшет қызып кеткендіктен өшірілді"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Телефоныңыз қалыпты жұмыс істеп тұр.\nТолық ақпарат алу үшін түртіңіз."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Құрылғыңыз қалыпты жұмыс істеп тұр.\nТолық ақпарат алу үшін түртіңіз."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Планшетіңіз қалыпты жұмыс істеп тұр.\nТолық ақпарат алу үшін түртіңіз."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Телефоныңыз қатты қызып кеткендіктен өшірілген еді. Ал қазір қалыпты жұмыс істеп тұр.\n\nОл мына жағдайларда қызып кетуі мүмкін:\n • ресурстарды көп көлемде қажет ететін қолданбаларды (ойын, бейне немесе навигация қолданбалары) пайдалану\n • үлкен көлемді файлдарды жүктеу немесе жүктеп салу;\n • телефонды жоғары температурада пайдалану."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Құрылғыңыз қатты қызып кеткендіктен өшірілген еді. Ал қазір қалыпты жұмыс істеп тұр.\n\nОл мына жағдайларда қызып кетуі мүмкін:\n • ресурстарды көп көлемде қажет ететін қолданбаларды (ойын, бейне немесе навигация қолданбалары) пайдалану;\n • үлкен көлемді файлдарды жүктеу немесе жүктеп салу;\n • құрылғыны жоғары температурада пайдалану."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Планшетіңіз қатты қызып кеткендіктен өшірілген еді. Ал қазір қалыпты жұмыс істеп тұр.\n\nОл мына жағдайларда қызып кетуі мүмкін:\n • ресурстарды көп көлемде қажет ететін қолданбаларды (ойын, бейне немесе навигация қолданбалары) пайдалану;\n • үлкен көлемді файлдарды жүктеу немесе жүктеп салу;\n • планшетті жоғары температурада пайдалану."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Телефон қызып бара жатыр"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Құрылғы қызып бара жатыр"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Планшет қызып бара жатыр"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Телефон толық суығанға дейін, кейбір функцияның жұмысы шектеледі.\nТолық ақпарат үшін түртіңіз."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Құрылғы толық суығанға дейін, кейбір функцияның жұмысы шектеледі.\nТолық ақпарат үшін түртіңіз."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Планшет толық суығанға дейін, кейбір функцияның жұмысы шектеледі.\nТолық ақпарат үшін түртіңіз."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Телефон автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nСуығаннан кейін, оның жұмысы қалпына келеді."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Құрылғы автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nСуығаннан кейін, оның жұмысы қалпына келеді."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Планшет автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nСуығаннан кейін, оның жұмысы қалпына келеді."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Саусақ ізін оқу сканері қуат түймесінде орналасқан. Ол – планшет шетіндегі шығыңқы дыбыс деңгейі түймесінің жанында орналасқан жалпақ түйме."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Саусақ ізін оқу сканері қуат түймесінде орналасқан. Ол – құрылғы шетіндегі шығыңқы дыбыс деңгейі түймесінің жанында орналасқан жалпақ түйме."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Саусақ ізін оқу сканері қуат түймесінде орналасқан. Ол – телефон шетіндегі шығыңқы дыбыс деңгейі түймесінің жанында орналасқан жалпақ түйме."</string>
diff --git a/packages/SystemUI/res-product/values-km/strings.xml b/packages/SystemUI/res-product/values-km/strings.xml
index 611ee94..34189d4 100644
--- a/packages/SystemUI/res-product/values-km/strings.xml
+++ b/packages/SystemUI/res-product/values-km/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"អ្នកបានព្យាយាមដោះសោទូរសព្ទនេះមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER">%d</xliff:g> ដងហើយ។ កម្រងព័ត៌មានការងារនេះនឹងត្រូវបានលុប ហើយវានឹងលុបទិន្នន័យកម្រងព័ត៌មានទាំងអស់។"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ បន្ទាប់ពីមានការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យ អ្នកនឹងត្រូវបានស្នើឱ្យដោះសោថេប្លេតរបស់អ្នក ដោយប្រើគណនីអ៊ីមែល។\n\n សូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដងហើយ។ បន្ទាប់ពីមានការព្យាយាមដោះសោចំនួន <xliff:g id="NUMBER_1">%2$d</xliff:g> ដងទៀតមិនទទួលបានជោគជ័យ អ្នកនឹងត្រូវបានស្នើឱ្យដោះសោទូរសព្ទរបស់អ្នកដោយប្រើគណនីអ៊ីមែល។\n\n សូមព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទីទៀត។"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ទូរសព្ទបានបិទដោយសារកម្ដៅ"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ឧបករណ៍បានបិទដោយសារកម្ដៅ"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ថេប្លេតបានបិទដោយសារកម្ដៅ"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"ឥឡូវនេះ ទូរសព្ទរបស់អ្នកកំពុងដំណើរការជាធម្មតា។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"ឥឡូវនេះ ឧបករណ៍របស់អ្នកកំពុងដំណើរការជាធម្មតា។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"ឥឡូវនេះ ថេប្លេតរបស់អ្នកកំពុងដំណើរការជាធម្មតា។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ទូរសព្ទរបស់អ្នកក្តៅពេក ដូច្នេះវាបានបិទដើម្បីបន្ថយកម្តៅ។ ឥឡូវនេះ ទូរសព្ទរបស់អ្នកកំពុងដំណើរការធម្មតា។\n\nទូរសព្ទរបស់អ្នកអាចនឹងឡើងកម្តៅខ្លាំងជ្រុល ប្រសិនបើអ្នក៖\n • ប្រើប្រាស់កម្មវិធីដែលប្រើប្រាស់ទិន្នន័យច្រើនក្នុងរយៈពេលខ្លី (ដូចជាហ្គេម វីដេអូ ឬកម្មវិធីរុករក)\n • ទាញយក ឬបង្ហោះឯកសារដែលមានទំហំធំ\n • ប្រើប្រាស់ទូរសព្ទរបស់អ្នកនៅកន្លែងមានសីតុណ្ហភាពខ្ពស់"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ឧបករណ៍របស់អ្នកក្តៅពេក ដូច្នេះវាបានបិទដើម្បីបន្ថយកម្តៅ។ ឥឡូវនេះ ឧបករណ៍របស់អ្នកកំពុងដំណើរការធម្មតា។\n\nឧបករណ៍របស់អ្នកអាចនឹងឡើងកម្តៅខ្លាំងជ្រុល ប្រសិនបើអ្នក៖\n • ប្រើប្រាស់កម្មវិធីដែលប្រើប្រាស់ទិន្នន័យច្រើនក្នុងរយៈពេលខ្លី (ដូចជាហ្គេម វីដេអូ ឬកម្មវិធីរុករក)\n • ទាញយក ឬបង្ហោះឯកសារដែលមានទំហំធំ\n • ប្រើប្រាស់ឧបករណ៍របស់អ្នកនៅកន្លែងមានសីតុណ្ហភាពខ្ពស់"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ថេប្លេតរបស់អ្នកក្តៅពេក ដូច្នេះវាបានបិទដើម្បីបន្ថយកម្តៅ។ ឥឡូវនេះ ថេប្លេតរបស់អ្នកកំពុងដំណើរការធម្មតា។\n\nថេប្លេតរបស់អ្នកអាចនឹងឡើងកម្តៅខ្លាំងជ្រុល ប្រសិនបើអ្នក៖\n • ប្រើប្រាស់កម្មវិធីដែលប្រើប្រាស់ទិន្នន័យច្រើនក្នុងរយៈពេលខ្លី (ដូចជាហ្គេម វីដេអូ ឬកម្មវិធីរុករក)\n • ទាញយក ឬបង្ហោះឯកសារដែលមានទំហំធំ\n • ប្រើប្រាស់ថេប្លេតរបស់អ្នកនៅកន្លែងមានសីតុណ្ហភាពខ្ពស់"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ទូរសព្ទកំពុងកើនកម្តៅ"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ឧបករណ៍កំពុងកើនកម្ដៅ"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ថេប្លេតកំពុងកើនកម្តៅ"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"មុខងារមួយចំនួននឹងមិនអាចប្រើបានពេញលេញនោះទេ ខណៈពេលដែលទូរសព្ទកំពុងបញ្ចុះកម្ដៅ។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"មុខងារមួយចំនួននឹងមិនអាចប្រើបានពេញលេញនោះទេ ខណៈពេលដែលឧបករណ៍កំពុងបញ្ចុះកម្ដៅ។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"មុខងារមួយចំនួននឹងមិនអាចប្រើបានពេញលេញនោះទេ ខណៈពេលដែលថេប្លេតកំពុងបញ្ចុះកម្ដៅ។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"ទូរសព្ទរបស់អ្នកនឹងព្យាយាមបញ្ចុះកម្តៅដោយស្វ័យប្រវត្តិ។ អ្នកនៅតែអាចប្រើទូរសព្ទរបស់អ្នកបានដដែល ប៉ុន្តែទូរសព្ទនេះអាចដំណើរការយឺតជាងមុន។\n\nនៅពេលទូរសព្ទរបស់អ្នកចុះត្រជាក់ហើយ ទូរសព្ទនេះនឹងដំណើរការធម្មតា។"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"ឧបករណ៍របស់អ្នកនឹងព្យាយាមបញ្ចុះកម្ដៅដោយស្វ័យប្រវត្តិ។ អ្នកនៅតែអាចប្រើឧបករណ៍របស់អ្នកបានដដែល ប៉ុន្តែឧបករណ៍នេះអាចដំណើរការយឺតជាងមុន។\n\nនៅពេលឧបករណ៍របស់អ្នកចុះត្រជាក់ហើយ ឧបករណ៍នេះនឹងដំណើរការធម្មតា។"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"ថេប្លេតរបស់អ្នកនឹងព្យាយាមបញ្ចុះកម្ដៅដោយស្វ័យប្រវត្តិ។ អ្នកនៅតែអាចប្រើថេប្លេតរបស់អ្នកបានដដែល ប៉ុន្តែថេប្លេតនេះអាចដំណើរការយឺតជាងមុន។\n\nនៅពេលថេប្លេតរបស់អ្នកចុះត្រជាក់ហើយ ថេប្លេតនេះនឹងដំណើរការធម្មតា។"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"សេនស័រចាប់ស្នាមម្រាមដៃស្ថិតនៅលើប៊ូតុងថាមពល។ វាជាប៊ូតុងរាបស្មើនៅជាប់នឹងប៊ូតុងកម្រិតសំឡេងដែលលៀនចេញមកនៅលើគែមថេប្លេត។"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"សេនស័រចាប់ស្នាមម្រាមដៃស្ថិតនៅលើប៊ូតុងថាមពល។ វាជាប៊ូតុងរាបស្មើនៅជាប់នឹងប៊ូតុងកម្រិតសំឡេងដែលលៀនចេញមកនៅលើគែមឧបករណ៍។"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"សេនស័រចាប់ស្នាមម្រាមដៃស្ថិតនៅលើប៊ូតុងថាមពល។ វាជាប៊ូតុងរាបស្មើនៅជាប់នឹងប៊ូតុងកម្រិតសំឡេងដែលលៀនចេញមកនៅលើគែមទូរសព្ទ។"</string>
diff --git a/packages/SystemUI/res-product/values-kn/strings.xml b/packages/SystemUI/res-product/values-kn/strings.xml
index 4fbf76f..4532d83 100644
--- a/packages/SystemUI/res-product/values-kn/strings.xml
+++ b/packages/SystemUI/res-product/values-kn/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಪ್ರೊಫೈಲ್ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನಿಮ್ಮನ್ನು ಕೇಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡ್ಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ನಿಮ್ಮನ್ನು ಕೇಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡ್ಗಳಲ್ಲಿ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ಫೋನ್ ಬಿಸಿಯಾದ ಕಾರಣದಿಂದಾಗಿ ಆಫ್ ಆಗಿದೆ"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ಸಾಧನ ಬಿಸಿಯಾದ ಕಾರಣದಿಂದಾಗಿ ಆಫ್ ಆಗಿದೆ"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ಟ್ಯಾಬ್ಲೆಟ್ ಬಿಸಿಯಾದ ಕಾರಣ ಆಫ್ ಆಗಿದೆ"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"ನಿಮ್ಮ ಫೋನ್ ಈಗ ಎಂದಿನಂತೆ ರನ್ ಆಗುತ್ತಿದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"ನಿಮ್ಮ ಸಾಧನವು ಈಗ ಎಂದಿನಂತೆ ರನ್ ಆಗುತ್ತಿದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಈಗ ಎಂದಿನಂತೆ ರನ್ ಆಗುತ್ತಿದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ನಿಮ್ಮ ಫೋನ್ ತುಂಬಾ ಬಿಸಿಯಾದ ಕಾರಣ ಅದನ್ನು ತಣ್ಣಗಾಗಿಸಲು ಆಫ್ ಮಾಡಲಾಗಿದೆ. ನಿಮ್ಮ ಫೋನ್ ಈಗ ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದೆ.\n\nನಿಮ್ಮ ಫೋನ್ ಈ ಕೆಳಗಿನ ಕಾರಣಗಳಿಂದ ತುಂಬಾ ಬಿಸಿಯಾಗಬಹುದು:\n • ಹೆಚ್ಚು ಸಂಪನ್ಮೂಲಗಳನ್ನು ಬಳಸಿಕೊಳ್ಳುವ ಆ್ಯಪ್ಗಳ ಬಳಕೆ (ಉದಾಹರಣೆಗೆ ಗೇಮಿಂಗ್, ವೀಡಿಯೊ ಅಥವಾ ನ್ಯಾವಿಗೇಶನ್ ಆ್ಯಪ್ಗಳು)\n • ದೊಡ್ಡ ಫೈಲ್ಗಳನ್ನು ಡೌನ್ಲೋಡ್ ಅಥವಾ ಅಪ್ಲೋಡ್ ಮಾಡುವುದು\n • ಅಧಿಕ ತಾಪಮಾನದಲ್ಲಿ ಫೋನ್ ಬಳಸುವುದು"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ನಿಮ್ಮ ಸಾಧನವು ತುಂಬಾ ಬಿಸಿಯಾದ ಕಾರಣ ಅದನ್ನು ತಣ್ಣಗಾಗಿಸಲು ಆಫ್ ಮಾಡಲಾಗಿದೆ. ನಿಮ್ಮ ಸಾಧನವು ಈಗ ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದೆ.\n\nನಿಮ್ಮ ಸಾಧನವು ಈ ಕೆಳಗಿನ ಕಾರಣಗಳಿಂದ ತುಂಬಾ ಬಿಸಿಯಾಗಬಹುದು:\n • ಹೆಚ್ಚು ಸಂಪನ್ಮೂಲಗಳನ್ನು ಬಳಸಿಕೊಳ್ಳುವ ಆ್ಯಪ್ಗಳ ಬಳಕೆ (ಉದಾಹರಣೆಗೆ ಗೇಮಿಂಗ್, ವೀಡಿಯೊ ಅಥವಾ ನ್ಯಾವಿಗೇಶನ್ ಆ್ಯಪ್ಗಳು)\n • ದೊಡ್ಡ ಫೈಲ್ಗಳನ್ನು ಡೌನ್ಲೋಡ್ ಅಥವಾ ಅಪ್ಲೋಡ್ ಮಾಡುವುದು\n • ಅಧಿಕ ತಾಪಮಾನದಲ್ಲಿ ಸಾಧನವನ್ನು ಬಳಸುವುದು"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ತುಂಬಾ ಬಿಸಿಯಾದ ಕಾರಣ ಅದನ್ನು ತಣ್ಣಗಾಗಿಸಲು ಆಫ್ ಮಾಡಲಾಗಿದೆ. ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಈಗ ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದೆ.\n\nನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಈ ಕೆಳಗಿನ ಕಾರಣಗಳಿಂದ ತುಂಬಾ ಬಿಸಿಯಾಗಬಹುದು:\n • ಹೆಚ್ಚು ಸಂಪನ್ಮೂಲಗಳನ್ನು ಬಳಸಿಕೊಳ್ಳುವ ಆ್ಯಪ್ಗಳ ಬಳಕೆ (ಉದಾಹರಣೆಗೆ ಗೇಮಿಂಗ್, ವೀಡಿಯೊ ಅಥವಾ ನ್ಯಾವಿಗೇಶನ್ ಆ್ಯಪ್ಗಳು)\n • ದೊಡ್ಡ ಫೈಲ್ಗಳನ್ನು ಡೌನ್ಲೋಡ್ ಅಥವಾ ಅಪ್ಲೋಡ್ ಮಾಡುವುದು\n • ಅಧಿಕ ತಾಪಮಾನದಲ್ಲಿ ಟ್ಯಾಬ್ಲೆಟ್ ಬಳಸುವುದು"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ಫೋನ್ ಬಿಸಿಯಾಗುತ್ತಿದೆ"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ಸಾಧನವು ಬಿಸಿಯಾಗುತ್ತಿದೆ"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ಟ್ಯಾಬ್ಲೆಟ್ ಬಿಸಿಯಾಗುತ್ತಿದೆ"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ಫೀಚರ್ಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸಲಾಗುತ್ತದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ಸಾಧನವು ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ಫೀಚರ್ಗಳು ಸೀಮಿತಗೊಳಿಸಲಾಗುತ್ತದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ಟ್ಯಾಬ್ಲೆಟ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ಫೀಚರ್ಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸಲಾಗುತ್ತದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"ನಿಮ್ಮ ಫೋನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದು, ಆದರೆ ಅದು ನಿಧಾನವಾಗಿ ರನ್ ಆಗಬಹುದು.\n\nಫೋನ್ ತಣ್ಣಗಾದ ನಂತರ ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ರನ್ ಆಗುತ್ತದೆ."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"ನಿಮ್ಮ ಸಾಧನವು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದು, ಆದರೆ ಅದು ನಿಧಾನವಾಗಿ ರನ್ ಆಗಬಹುದು.\n\nಸಾಧನವು ತಣ್ಣಗಾದ ನಂತರ, ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ರನ್ ಆಗುತ್ತದೆ."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದು, ಆದರೆ ಅದು ನಿಧಾನವಾಗಿ ರನ್ ಆಗಬಹುದು.\n\nಟ್ಯಾಬ್ಲೆಟ್ ತಣ್ಣಗಾದ ನಂತರ, ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ರನ್ ಆಗುತ್ತದೆ."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಪವರ್ ಬಟನ್ನಲ್ಲಿದೆ. ಇದು ಟ್ಯಾಬ್ಲೆಟ್ನ ಅಂಚಿನಲ್ಲಿರುವ ಎತ್ತರಿಸಿದ ವಾಲ್ಯೂಮ್ ಬಟನ್ನ ಪಕ್ಕದಲ್ಲಿರುವ ಫ್ಲ್ಯಾಟ್ ಬಟನ್ ಆಗಿದೆ."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಪವರ್ ಬಟನ್ನಲ್ಲಿದೆ. ಇದು ಸಾಧನದ ಅಂಚಿನಲ್ಲಿರುವ ಎತ್ತರಿಸಿದ ವಾಲ್ಯೂಮ್ ಬಟನ್ನ ಪಕ್ಕದಲ್ಲಿರುವ ಫ್ಲಾಟ್ ಬಟನ್ ಆಗಿದೆ."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಪವರ್ ಬಟನ್ನಲ್ಲಿದೆ. ಇದು ಫೋನ್ನ ಅಂಚಿನಲ್ಲಿರುವ ಎತ್ತರಿಸಿದ ವಾಲ್ಯೂಮ್ ಬಟನ್ನ ಪಕ್ಕದಲ್ಲಿರುವ ಫ್ಲ್ಯಾಟ್ ಬಟನ್ ಆಗಿದೆ."</string>
diff --git a/packages/SystemUI/res-product/values-ko/strings.xml b/packages/SystemUI/res-product/values-ko/strings.xml
index b262452..cb4a620 100644
--- a/packages/SystemUI/res-product/values-ko/strings.xml
+++ b/packages/SystemUI/res-product/values-ko/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필과 모든 프로필 데이터가 삭제됩니다."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"잠금 해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금 해제해야 합니다.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"잠금 해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금 해제해야 합니다.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"발열로 인해 휴대전화가 꺼짐"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"발열로 인해 기기가 꺼짐"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"발열로 인해 태블릿이 꺼짐"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"이제 휴대전화가 정상적으로 작동합니다.\n자세히 알아보려면 탭하세요."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"이제 기기가 정상적으로 작동합니다.\n자세히 알아보려면 탭하세요."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"이제 태블릿이 정상적으로 작동합니다.\n자세히 알아보려면 탭하세요."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"휴대전화가 과열되어 온도를 낮추기 위해 전원이 종료되었습니다. 지금은 휴대전화가 정상적으로 작동합니다.\n\n휴대전화가 과열되는 이유는 다음과 같습니다.\n • 리소스를 많이 사용하는 앱 사용(예: 게임, 동영상 또는 내비게이션 앱)\n • 대용량 파일을 다운로드 또는 업로드\n • 온도가 높은 곳에서 휴대전화 사용"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"기기가 과열되어 온도를 낮추기 위해 전원이 종료되었습니다. 지금은 기기가 정상적으로 작동합니다.\n\n기기가 과열되는 이유는 다음과 같습니다.\n • 리소스를 많이 사용하는 앱 사용(예: 게임, 동영상 또는 내비게이션 앱)\n • 대용량 파일을 다운로드 또는 업로드\n • 온도가 높은 곳에서 기기 사용"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"태블릿이 과열되어 온도를 낮추기 위해 전원이 종료되었습니다. 지금은 태블릿이 정상적으로 작동합니다.\n\n태블릿이 과열되는 이유는 다음과 같습니다.\n • 리소스를 많이 사용하는 앱 사용(예: 게임, 동영상 또는 내비게이션 앱)\n • 대용량 파일을 다운로드 또는 업로드\n • 온도가 높은 곳에서 태블릿 사용"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"휴대전화 온도가 높음"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"기기 온도가 높음"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"태블릿 온도가 높음"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다.\n자세히 알아보려면 탭하세요."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"기기 온도를 낮추는 동안 일부 기능이 제한됩니다.\n자세히 알아보려면 탭하세요."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"태블릿 온도를 낮추는 동안 일부 기능이 제한됩니다.\n자세히 알아보려면 탭하세요."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"휴대전화가 자동으로 온도를 낮추려고 시도합니다. 휴대전화를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n휴대전화 온도가 낮아지면 정상적으로 작동됩니다."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"기기가 자동으로 온도를 낮추려고 시도합니다. 기기를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n기기 온도가 낮아지면 정상적으로 작동됩니다."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"태블릿이 자동으로 온도를 낮추려고 시도합니다. 태블릿을 계속 사용할 수 있지만 작동이 느려질 수도 있습니다.\n\n태블릿 온도가 낮아지면 정상적으로 작동합니다."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"지문 센서는 전원 버튼에 있습니다. 태블릿 옆면에 있는 튀어나온 볼륨 버튼 옆의 평평한 버튼입니다."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"지문 센서는 전원 버튼에 있습니다. 기기 옆면에 있는 튀어나온 볼륨 버튼 옆의 평평한 버튼입니다."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"지문 센서는 전원 버튼에 있습니다. 휴대전화 옆면에 있는 튀어나온 볼륨 버튼 옆의 평평한 버튼입니다."</string>
diff --git a/packages/SystemUI/res-product/values-ky/strings.xml b/packages/SystemUI/res-product/values-ky/strings.xml
index 0f6acfc..8bd066f0 100644
--- a/packages/SystemUI/res-product/values-ky/strings.xml
+++ b/packages/SystemUI/res-product/values-ky/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Телефондун кулпусун <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес ачууга аракет жасадыңыз. Жумуш профили өчүрүлүп, андагы бардык нерселер өчүрүлөт."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин планшетиңизди бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес тарттыңыз. Дагы <xliff:g id="NUMBER_1">%2$d</xliff:g> ийгиликсиз аракеттен кийин телефонуңузду бөгөттөн электрондук почтаңыз аркылуу чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секунддан кийин кайра аракеттениңиз."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Телефон ысыгандыктан өчүрүлдү"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Түзмөк ысыгандыктан өчүрүлдү"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Планшет ысыгандыктан өчүрүлдү"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Телефонуңуз кадимкидей иштеп жатат.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Түзмөгүңүз кадимкидей иштеп жатат.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Планшетиңиз кадимкидей иштеп жатат.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Телефонуңуз өтө ысып кеткендиктен, аны муздатуу үчүн өчүрүлдү. Эми телефонуңуз кадимкидей иштеп жатат.\n\nТелефонуңуз төмөнкү шарттарда ысып кетиши мүмкүн:\n • Ашыкча ресурс короткон колдонмолорду (оюндар, видео же чабыттоо колдонмолору) пайдалансаңыз \n • Ири көлөмдөгү файлдарды жүктөп алсаңыз же берсеңиз\n • Телефонуңузду жогорку температураларда пайдалансаңыз"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Түзмөгүңүз өтө ысып кеткендиктен, аны муздатуу үчүн өчүрүлдү. Эми түзмөгүңүз кадимкидей иштеп жатат.\n\nТүзмөгүңүз төмөнкү шарттарда ысып кетиши мүмкүн:\n • Ашыкча ресурс короткон колдонмолорду (оюндар, видео же чабыттоо колдонмолору) пайдалансаңыз \n • Ири көлөмдөгү файлдарды жүктөп алсаңыз же берсеңиз\n • Түзмөгүңүздү жогорку температураларда пайдалансаңыз"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Планшетиңиз өтө ысып кеткендиктен, аны муздатуу үчүн өчүрүлдү. Эми планшетиңиз кадимкидей иштеп жатат.\n\nПланшетиңиз төмөнкү шарттарда ысып кетиши мүмкүн:\n • Ашыкча ресурс короткон колдонмолорду (оюндар, видео же чабыттоо колдонмолору) пайдалансаңыз \n • Ири көлөмдөгү файлдарды жүктөп алсаңыз же берсеңиз\n • Планшетиңизди жогорку температураларда пайдалансаңыз"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Телефон ысып баратат"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Түзмөк ысып баратат"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Планшет ысып баратат"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Телефон сууганча айрым элементтердин иши чектелген.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Түзмөк сууганча айрым элементтердин иши чектелген.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Планшет сууганча айрым элементтердин иши чектелген.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Телефонуңуз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТелефонуңуз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Түзмөгүңүз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТүзмөгүңүз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Планшетиңиз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nПланшетиңиз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Манжа изинин сенсору кубат баскычында жайгашкан. Бул планшеттин четиндеги үндү катуулатуу/акырындатуу баскычынын (көтөрүлгөн) жанындагы жалпак баскыч."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Манжа изинин сенсору кубат баскычында жайгашкан. Бул түзмөктүн четиндеги үндү катуулатуу/акырындатуу баскычынын (көтөрүлгөн) жанындагы жалпак баскыч."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Манжа изинин сенсору кубат баскычында жайгашкан. Бул телефондун четиндеги үндү катуулатуу/акырындатуу баскычынын (көтөрүлгөн) жанындагы жалпак баскыч."</string>
diff --git a/packages/SystemUI/res-product/values-lo/strings.xml b/packages/SystemUI/res-product/values-lo/strings.xml
index fee741d..958cf32 100644
--- a/packages/SystemUI/res-product/values-lo/strings.xml
+++ b/packages/SystemUI/res-product/values-lo/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບຜິດ <xliff:g id="NUMBER">%d</xliff:g> ເທື່ອແລ້ວ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກລຶບອອກ, ເຊິ່ງຈະລຶບຂໍ້ມູນໂປຣໄຟລ໌ທັງໝົດອອກນຳ."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດໂທລະສັບຂອງທ່ານດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ບັນຊີອີເມວ.\n\n ກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ໂທລະສັບປິດເຄື່ອງເນື່ອງຈາກຮ້ອນເກີນໄປ"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ອຸປະກອນປິດເຄື່ອງເນື່ອງຈາກຮ້ອນເກີນໄປ"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ແທັບເລັດປິດເຄື່ອງເນື່ອງຈາກຮ້ອນເກີນໄປ"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"ຕອນນີ້ໂທລະສັບຂອງທ່ານເຮັດວຽກຕາມປົກກະຕິແລ້ວ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"ຕອນນີ້ອຸປະກອນຂອງທ່ານເຮັດວຽກຕາມປົກກະຕິແລ້ວ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"ຕອນນີ້ແທັບເລັດຂອງທ່ານເຮັດວຽກຕາມປົກກະຕິແລ້ວ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ໂທລະສັບຂອງທ່ານຮ້ອນເກີນໄປ, ດັ່ງນັ້ນຈຶ່ງຖືກປິດເຄື່ອງເພື່ອໃຫ້ເຢັນລົງ. ຕອນນີ້ໂທລະສັບຂອງທ່ານເຮັດວຽກຕາມປົກກະຕິແລ້ວ.\n\nໂທລະສັບຂອງທ່ານອາດຮ້ອນເກີນໄປ ຫາກທ່ານ:\n • ໃຊ້ແອັບທີ່ກິນຊັບພະຍາກອນຫຼາຍ (ເຊັ່ນ: ເກມ, ວິດີໂອ ຫຼື ແອັບການນຳທາງ)\n • ດາວໂຫຼດ ຫຼື ອັບໂຫຼດໄຟລ໌ຂະໜາດໃຫຍ່\n • ໃຊ້ໂທລະສັບຂອງທ່ານໃນອຸນຫະພູມທີ່ສູງ"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ອຸປະກອນຂອງທ່ານຮ້ອນເກີນໄປ, ດັ່ງນັ້ນຈຶ່ງຖືກປິດເຄື່ອງເພື່ອໃຫ້ເຢັນລົງ. ຕອນນີ້ອຸປະກອນຂອງທ່ານເຮັດວຽກຕາມປົກກະຕິແລ້ວ.\n\nອຸປະກອນຂອງທ່ານອາດຮ້ອນເກີນໄປ ຫາກທ່ານ:\n • ໃຊ້ແອັບທີ່ກິນຊັບພະຍາກອນຫຼາຍ (ເຊັ່ນ: ເກມ, ວິດີໂອ ຫຼື ແອັບການນຳທາງ)\n • ດາວໂຫຼດ ຫຼື ອັບໂຫຼດໄຟລ໌ຂະໜາດໃຫຍ່\n • ໃຊ້ອຸປະກອນຂອງທ່ານໃນອຸນຫະພູມທີ່ສູງ"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ແທັບເລັດຂອງທ່ານຮ້ອນເກີນໄປ, ດັ່ງນັ້ນຈຶ່ງຖືກປິດເຄື່ອງເພື່ອໃຫ້ເຢັນລົງ. ຕອນນີ້ແທັບເລັດຂອງທ່ານເຮັດວຽກຕາມປົກກະຕິແລ້ວ.\n\nແທັບເລັດຂອງທ່ານອາດຮ້ອນເກີນໄປ ຫາກທ່ານ:\n • ໃຊ້ແອັບທີ່ກິນຊັບພະຍາກອນຫຼາຍ (ເຊັ່ນ: ເກມ, ວິດີໂອ ຫຼື ແອັບການນຳທາງ)\n • ດາວໂຫຼດ ຫຼື ອັບໂຫຼດໄຟລ໌ຂະໜາດໃຫຍ່\n • ໃຊ້ແທັບເລັດຂອງທ່ານໃນອຸນຫະພູມທີ່ສູງ"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ໂທລະສັບເລີ່ມຮ້ອນຂຶ້ນ"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ອຸປະກອນເລີ່ມຮ້ອນຂຶ້ນ"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ແທັບເລັດເລີ່ມຮ້ອນຂຶ້ນ"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ຄຸນສົມບັດບາງຢ່າງອາດໃຊ້ໄດ້ແບບຈຳກັດໃນລະຫວ່າງທີ່ໂທລະສັບເຢັນລົງ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ຄຸນສົມບັດບາງຢ່າງອາດໃຊ້ໄດ້ແບບຈຳກັດໃນລະຫວ່າງທີ່ອຸປະກອນເຢັນລົງ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ຄຸນສົມບັດບາງຢ່າງອາດໃຊ້ໄດ້ແບບຈຳກັດໃນລະຫວ່າງທີ່ແທັບເລັດເຢັນລົງ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"ໂທລະສັບຂອງທ່ານຈະພະຍາຍາມຫຼຸດອຸນຫະພູມລົງໂດຍອັດຕະໂນມັດ. ທ່ານຍັງສາມາດໃຊ້ໂທລະສັບຂອງທ່ານໄດ້ຢູ່, ແຕ່ໂທລະສັບອາດເຮັດວຽກຊ້າລົງ.\n\nໂທລະສັບຂອງທ່ານຈະກັບມາເຮັດວຽກຕາມປົກກະຕິເມື່ອເຢັນລົງແລ້ວ."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"ອຸປະກອນຂອງທ່ານຈະພະຍາຍາມເຮັດໃຫ້ເຢັນລົງໂດຍອັດຕະໂນມັດ. ທ່ານຍັງສາມາດໃຊ້ອຸປະກອນຂອງທ່ານໄດ້ຢູ່, ແຕ່ອຸປະກອນອາດເຮັດວຽກຊ້າລົງ.\n\nອຸປະກອນຂອງທ່ານຈະກັບມາເຮັດວຽກຕາມປົກກະຕິເມື່ອເຢັນລົງແລ້ວ."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"ແທັບເລັດຂອງທ່ານຈະພະຍາຍາມເຮັດໃຫ້ເຢັນລົງໂດຍອັດຕະໂນມັດ. ທ່ານຍັງສາມາດໃຊ້ແທັບເລັດຂອງທ່ານໄດ້ຢູ່, ແຕ່ແທັບເລັດອາດເຮັດວຽກຊ້າລົງ.\n\nແທັບເລັດຂອງທ່ານຈະກັບມາເຮັດວຽກຕາມປົກກະຕິເມື່ອເຢັນລົງແລ້ວ."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ເຊັນເຊີລາຍນິ້ວມືແມ່ນຢູ່ປຸ່ມເປີດປິດ. ມັນເປັນປຸ່ມແປໆທີ່ຢູ່ຖັດຈາກປຸ່ມລະດັບສຽງຢູ່ຂອບຂອງແທັບເລັດ."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ເຊັນເຊີລາຍນິ້ວມືແມ່ນຢູ່ປຸ່ມເປີດປິດ. ມັນເປັນປຸ່ມແປໆທີ່ຢູ່ຖັດຈາກປຸ່ມລະດັບສຽງຢູ່ຂອບຂອງອຸປະກອນ."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ເຊັນເຊີລາຍນິ້ວມືແມ່ນຢູ່ປຸ່ມເປີດປິດ. ມັນເປັນປຸ່ມແປໆທີ່ຢູ່ຖັດຈາກປຸ່ມລະດັບສຽງຢູ່ຂອບຂອງໂທລະສັບ."</string>
diff --git a/packages/SystemUI/res-product/values-lt/strings.xml b/packages/SystemUI/res-product/values-lt/strings.xml
index 3035e4f..989e411 100644
--- a/packages/SystemUI/res-product/values-lt/strings.xml
+++ b/packages/SystemUI/res-product/values-lt/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> kart. netinkamai nupiešėte atrakinimo piešinį. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami el. pašto paskyrą.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefonas išjungtas, nes įkaito"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Įrenginys išjungtas, nes įkaito"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Planšetinis komp. išjungtas, nes įkaito"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefonas dabar veikia įprastai.\nPalietę gausite daugiau informacijos"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Įrenginys dabar veikia įprastas.\nPalietę gausite daugiau informacijos"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Planšetinis kompiuteris dabar veikia įprastai.\nPalietę gausite daugiau informacijos"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefonas per daug įkaito, todėl buvo išjungtas, kad atvėstų. Dabar telefonas veikia įprastai.\n\nTelefonas gali per daug įkaisti, jei:\n • esate įjungę daug išteklių naudojančių programų (pvz., žaidimų, vaizdo įrašų arba navigacijos programų);\n • atsisiunčiate arba įkeliate didelius failus;\n • telefoną naudojate esant aukštai temperatūrai."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Įrenginys per daug įkaito, todėl buvo išjungtas, kad atvėstų. Dabar įrenginys veikia įprastai.\n\nĮrenginys gali per daug įkaisti, jei:\n • esate įjungę daug išteklių naudojančių programų (pvz., žaidimų, vaizdo įrašų arba navigacijos programų);\n • atsisiunčiate arba įkeliate didelius failus;\n • įrenginį naudojate esant aukštai temperatūrai."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Planšetinis kompiuteris per daug įkaito, todėl buvo išjungtas, kad atvėstų. Dabar planšetinis kompiuteris veikia įprastai.\n\nPlanšetinis kompiuteris gali per daug įkaisti, jei:\n • esate įjungę daug išteklių naudojančių programų (pvz., žaidimų, vaizdo įrašų arba navigacijos programų);\n • atsisiunčiate arba įkeliate didelius failus;\n • planšetinį kompiuterį naudojate esant aukštai temperatūrai."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefonas kaista"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Įrenginys kaista"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Planšetinis kompiuteris kaista"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta.\nPalietę gausite daugiau informacijos"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Kai kurios funkcijos gali neveikti, kol įrenginys vėsta.\nPalietę gausite daugiau informacijos"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Kai kurios funkcijos gali neveikti, kol planšetinis kompiuteris vėsta.\nPalietę gausite daugiau informacijos"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefonas automatiškai bandys atvėsti. Telefoną vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai telefonas atvės, jis veiks įprastai."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Įrenginys automatiškai bandys atvėsti. Įrenginį vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai įrenginys atvės, jis veiks įprastai."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Planšetinis kompiuteris automatiškai bandys atvėsti. Planšetinį kompiuterį vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai planšetinis kompiuteris atvės, jis veiks įprastai."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Piršto atspaudo jutiklis yra ant maitinimo mygtuko. Tai yra plokščias mygtukas šalia iškilusio garsumo mygtuko ant planšetinio kompiuterio krašto."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Piršto atspaudo jutiklis yra ant maitinimo mygtuko. Tai yra plokščias mygtukas šalia iškilusio garsumo mygtuko ant įrenginio krašto."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Piršto atspaudo jutiklis yra ant maitinimo mygtuko. Tai yra plokščias mygtukas šalia iškilusio garsumo mygtuko ant telefono krašto."</string>
diff --git a/packages/SystemUI/res-product/values-lv/strings.xml b/packages/SystemUI/res-product/values-lv/strings.xml
index 8e9c064d..a18076a 100644
--- a/packages/SystemUI/res-product/values-lv/strings.xml
+++ b/packages/SystemUI/res-product/values-lv/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizi(-es) nesekmīgi mēģinājāt atbloķēt tālruni. Darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīga(-iem) mēģinājuma(-iem) planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizi(-es) nepareizi norādījāt atbloķēšanas kombināciju. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīga(-iem) mēģinājuma(-iem) tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundes(-ēm)."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Tālrunis izslēgts karstuma dēļ"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Ierīce izslēgta karstuma dēļ"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Planšetdators izslēgts karstuma dēļ"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Tagad jūsu tālrunis darbojas normāli.\nPieskarieties, lai uzzinātu vairāk."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Tagad jūsu ierīce darbojas normāli.\nPieskarieties, lai uzzinātu vairāk."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tagad jūsu planšetdators darbojas normāli.\nPieskarieties, lai uzzinātu vairāk."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Jūsu tālrunis bija pārkarsis un tika izslēgts. Tagad tas darbojas normāli.\n\nTālrunis var sakarst, ja:\n • tiek izmantotas lietotnes, kas patērē daudz enerģijas (piem., spēles, video lietotnes vai navigācija);\n • tiek lejupielādēti/augšupielādēti lieli faili;\n • tālrunis tiek lietots augstā temperatūrā."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Jūsu ierīce bija pārkarsusi un tika izslēgta. Tagad tā darbojas normāli.\n\nIerīce var sakarst, ja:\n • tiek izmantotas lietotnes, kas patērē daudz enerģijas (piem., spēles, video lietotnes vai navigācija);\n • tiek lejupielādēti/augšupielādēti lieli faili;\n • ierīce tiek lietota augstā temperatūrā."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Jūsu planšetdators bija pārkarsis un tika izslēgts. Tagad tas darbojas normāli.\n\nPlanšetdators var sakarst, ja:\n • tiek izmantotas lietotnes, kas patērē daudz enerģijas (piem., spēles, video lietotnes vai navigācija);\n • tiek lejupielādēti/augšupielādēti lieli faili;\n • planšetdators tiek lietots augstā temperatūrā."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Tālrunis kļūst silts"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Ierīce kļūst silta"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Planšetdators kļūst silts"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Dažas funkcijas ir ierobežotas, kamēr notiek tālruņa atdzišana.\nPieskarieties, lai uzzinātu vairāk."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Dažas funkcijas ir ierobežotas, kamēr notiek ierīces atdzišana.\nPieskarieties, lai uzzinātu vairāk."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Dažas funkcijas ir ierobežotas, kamēr notiek planšetdatora atdzišana.\nPieskarieties, lai uzzinātu vairāk."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Jūsu tālrunis automātiski mēģinās atdzist. Jūs joprojām varat izmantot tālruni, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz tālrunis būs atdzisis, tas darbosies normāli."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Jūsu ierīce automātiski mēģinās atdzist. Jūs joprojām varat izmantot ierīci, taču tā, iespējams, darbosies lēnāk.\n\nTiklīdz ierīce būs atdzisusi, tā darbosies normāli."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Jūsu planšetdators automātiski mēģinās atdzist. Jūs joprojām varat izmantot planšetdatoru, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz planšetdators būs atdzisis, tas darbosies normāli."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Pirksta nospieduma sensors atrodas uz barošanas pogas. Tā ir plakanā poga, kas atrodas blakus augstākai skaļuma pogai planšetdatora sānos."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Pirksta nospieduma sensors atrodas uz barošanas pogas. Tā ir plakanā poga, kas atrodas blakus augstākai skaļuma pogai ierīces sānos."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Pirksta nospieduma sensors atrodas uz barošanas pogas. Tā ir plakanā poga, kas atrodas blakus augstākai skaļuma pogai tālruņa sānos."</string>
diff --git a/packages/SystemUI/res-product/values-mk/strings.xml b/packages/SystemUI/res-product/values-mk/strings.xml
index 6d34f97..bb58df2 100644
--- a/packages/SystemUI/res-product/values-mk/strings.xml
+++ b/packages/SystemUI/res-product/values-mk/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Погрешно ја употребивте вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите таблетот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Погрешно ја употребивте вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараме да го отклучите телефонот со сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Телефонот се исклучи поради загреаност"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Уредот се исклучи поради загреаност"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Таблетот се исклучи поради загреаност"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Сега телефонот работи нормално.\nДопрете за повеќе информации"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Сега уредот работи нормално.\nДопрете за повеќе информации"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Сега таблетот работи нормално.\nДопрете за повеќе информации"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Телефонот беше премногу загреан, така што се исклучи за да се олади. Сега работи нормално.\n\nТелефонот може премногу да се загрее ако:\n • користите апликации што користат многу ресурси (како што се, на пример, апликациите за видеа, навигација или игри)\n • преземате или поставувате големи датотеки\n • го користите телефонот на високи температури"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Уредот беше премногу загреан, така што се исклучи за да се олади. Сега работи нормално.\n\nУредот може премногу да се загрее ако:\n • користите апликации што користат многу ресурси (како што се, на пример, апликациите за видеа, навигација или игри)\n • преземате или прикачувате големи датотеки\n • го користите уредот на високи температури"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Таблетот беше премногу загреан, така што се исклучи за да се олади. Сега работи нормално.\n\nТаблетот може премногу да се загрее ако:\n • користите апликации што користат многу ресурси (како што се, на пример, апликациите за видеа, навигација или игри)\n • преземате или поставувате големи датотеки\n • го користите таблетот на високи температури"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Телефонот се загрева"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Уредот се загрева"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Таблетот се загрева"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Некои функции се ограничени додека телефонот се лади.\nДопрете за повеќе информации"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Некои функции се ограничени додека уредот се лади.\nДопрете за повеќе информации"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Некои функции се ограничени додека таблетот се лади.\nДопрете за повеќе информации"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Телефонот автоматски ќе почне да се лади. Сѐ уште ќе може да го користите, но можно е да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Уредот автоматски ќе почне да се лади. Сѐ уште ќе може да го користите, но можно е да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Таблетот автоматски ќе почне да се лади. Сѐ уште ќе може да го користите, но можно е да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сензорот за отпечатоци се наоѓа на копчето за вклучување. Тоа е рамното копче веднаш до подигнатото копче за јачина на звук на работ од таблетот."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сензорот за отпечатоци се наоѓа на копчето за вклучување. Тоа е рамното копче веднаш до подигнатото копче за јачина на звук на работ од уредот."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сензорот за отпечатоци се наоѓа на копчето за вклучување. Тоа е рамното копче веднаш до подигнатото копче за јачина на звук на работ од телефонот."</string>
diff --git a/packages/SystemUI/res-product/values-ml/strings.xml b/packages/SystemUI/res-product/values-ml/strings.xml
index d1e7b4b..55cfd06 100644
--- a/packages/SystemUI/res-product/values-ml/strings.xml
+++ b/packages/SystemUI/res-product/values-ml/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"നിങ്ങൾ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായ രീതിയിൽ ഫോൺ അൺലോക്ക് ചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കം ചെയ്യപ്പെടുകയും, അതുവഴി എല്ലാ പ്രൊഫൈൽ ഡാറ്റയും ഇല്ലാതാകുകയും ചെയ്യും."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായ രീതിയിൽ അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ടാബ്ലെറ്റ് അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"നിങ്ങൾ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായ രീതിയിൽ അൺലോക്ക് പാറ്റേൺ വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി പരാജയപ്പെട്ടാൽ, ഒരു ഇമെയിൽ അക്കൗണ്ടുപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കന്റ് കഴിഞ്ഞ് വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ചൂട് കൂടിയതിനാൽ ഫോൺ ഓഫായി"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ചൂട് കൂടിയതിനാൽ ഉപകരണം ഓഫായി"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ചൂട് കൂടിയതിനാൽ ടാബ്ലെറ്റ് ഓഫായി"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"നിങ്ങളുടെ ഫോൺ ഇപ്പോൾ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കുന്നുണ്ട്.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കുന്നുണ്ട്.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"നിങ്ങളുടെ ടാബ്ലെറ്റ് ഇപ്പോൾ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കുന്നുണ്ട്.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ഫോൺ വളരെയധികം ചൂടായതിനാൽ തണുക്കാൻ വേണ്ടിയാണ് ഓഫായത്. ഫോൺ ഇപ്പോൾ സാധാരണഗതിയിൽ പ്രവർത്തിക്കുന്നുണ്ട്.\n\nഇനിപ്പറയുന്ന സാഹചര്യങ്ങളിൽ ഫോൺ വളരെയധികം ചൂടായേക്കാം:\n • ഗെയിമിംഗ്, വീഡിയോ അല്ലെങ്കിൽ നാവിഗേഷൻ തുടങ്ങിയ കൂടുതൽ വിഭവങ്ങൾ ഉപയോഗിക്കുന്ന ആപ്പുകൾ ഉപയോഗിക്കുന്നത്\n • വലിയ ഫയലുകൾ അപ്ലോഡോ ഡൗൺലോഡോ ചെയ്യുന്നത്\n • ഉയർന്ന താപനിലയിൽ ഫോൺ ഉപയോഗിക്കുന്നത്"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ഉപകരണം വളരെയധികം ചൂടായതിനാൽ തണുക്കാൻ വേണ്ടിയാണ് ഓഫായത്. ഉപകരണം ഇപ്പോൾ സാധാരണഗതിയിൽ പ്രവർത്തിക്കുന്നുണ്ട്.\n\nഇനിപ്പറയുന്ന സാഹചര്യങ്ങളിൽ ഉപകരണം വളരെയധികം ചൂടായേക്കാം:\n • ഗെയിമിംഗ്, വീഡിയോ അല്ലെങ്കിൽ നാവിഗേഷൻ തുടങ്ങിയ കൂടുതൽ വിഭവങ്ങൾ ഉപയോഗിക്കുന്ന ആപ്പുകൾ ഉപയോഗിക്കുന്നത്\n • വലിയ ഫയലുകൾ അപ്ലോഡോ ഡൗൺലോഡോ ചെയ്യുന്നത്\n • ഉയർന്ന താപനിലയിൽ ഉപകരണം ഉപയോഗിക്കുന്നത്"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ടാബ്ലെറ്റ് വളരെയധികം ചൂടായതിനാൽ തണുക്കാൻ വേണ്ടിയാണ് ഓഫായത്. ടാബ്ലെറ്റ് ഇപ്പോൾ സാധാരണഗതിയിൽ പ്രവർത്തിക്കുന്നുണ്ട്.\n\nഇനിപ്പറയുന്ന സാഹചര്യങ്ങളിൽ ടാബ്ലെറ്റ് വളരെയധികം ചൂടായേക്കാം:\n • ഗെയിമിംഗ്, വീഡിയോ അല്ലെങ്കിൽ നാവിഗേഷൻ തുടങ്ങിയ കൂടുതൽ വിഭവങ്ങൾ ഉപയോഗിക്കുന്ന ആപ്പുകൾ ഉപയോഗിക്കുന്നത്\n • വലിയ ഫയലുകൾ അപ്ലോഡോ ഡൗൺലോഡോ ചെയ്യുന്നത്\n • ഉയർന്ന താപനിലയിൽ ടാബ്ലെറ്റ് ഉപയോഗിക്കുന്നത്"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ഫോൺ ചൂടാകുന്നു"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ഉപകരണം ചൂടാകുന്നു"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ടാബ്ലെറ്റ് ചൂടാകുന്നു"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ഫോൺ തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തും.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ഉപകരണം തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തും.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ടാബ്ലെറ്റ് തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തും.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"നിങ്ങളുടെ ഫോൺ സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഫോൺ ഉപയോഗിക്കാമെങ്കിലും അതിന്റെ പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കാം.\n\nതണുത്തുകഴിഞ്ഞാൽ ഫോൺ സാധാരണപോലെ പ്രവർത്തിക്കും."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"നിങ്ങളുടെ ഉപകരണം സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഉപകരണം ഉപയോഗിക്കാമെങ്കിലും അതിന്റെ പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കാം.\n\nതണുത്തുകഴിഞ്ഞാൽ ഉപകരണം സാധാരണപോലെ പ്രവർത്തിക്കും."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"നിങ്ങളുടെ ടാബ്ലെറ്റ് സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ടാബ്ലെറ്റ് ഉപയോഗിക്കാമെങ്കിലും അതിന്റെ പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കാം.\n\nതണുത്തുകഴിഞ്ഞാൽ ടാബ്ലെറ്റ് സാധാരണപോലെ പ്രവർത്തിക്കും."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"പവർ ബട്ടണിലാണ് ഫിംഗർപ്രിന്റ് സെൻസർ ഉള്ളത്. ടാബ്ലെറ്റിന്റെ അറ്റത്ത് ഉയർന്ന് നിൽക്കുന്ന ശബ്ദ ബട്ടണിന്റെ അടുത്തുള്ള പരന്ന ബട്ടൺ ആണ് ഇത്."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"പവർ ബട്ടണിലാണ് ഫിംഗർപ്രിന്റ് സെൻസർ ഉള്ളത്. ഉപകരണത്തിന്റെ അറ്റത്ത് ഉയർന്ന് നിൽക്കുന്ന ശബ്ദ ബട്ടണിന്റെ അടുത്തുള്ള പരന്ന ബട്ടൺ ആണ് ഇത്."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"പവർ ബട്ടണിലാണ് ഫിംഗർപ്രിന്റ് സെൻസർ ഉള്ളത്. ഫോണിന്റെ അറ്റത്ത് ഉയർന്ന് നിൽക്കുന്ന ശബ്ദ ബട്ടണിന്റെ അടുത്തുള്ള പരന്ന ബട്ടൺ ആണ് ഇത്."</string>
diff --git a/packages/SystemUI/res-product/values-mn/strings.xml b/packages/SystemUI/res-product/values-mn/strings.xml
index 1cc1a1c..179e816 100644
--- a/packages/SystemUI/res-product/values-mn/strings.xml
+++ b/packages/SystemUI/res-product/values-mn/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу хийсэн байна. Ажлын профайлыг устгах бөгөөд ингэснээр профайлын бүх өгөгдлийг устгах болно."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Та тайлах хээгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурсан байна. Дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу зурсны дараа та имэйл бүртгэл ашиглан таблетынхаа түгжээг тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Та тайлах хээгээ <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурсан байна. Дахин <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу зурсны дараа та имэйл бүртгэл ашиглан утасныхаа түгжээг тайлах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Халсны улмаас утас унтарсан"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Халсны улмаас төхөөрөмж унтарсан"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Халсны улмаас таблет унтарсан"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Таны утас одоо хэвийн ажиллаж байна.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Таны төхөөрөмж одоо хэвийн ажиллаж байна.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Таны таблет одоо хэвийн ажиллаж байна.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Таны утас хэт халсан тул хөрөхөөр унтарсан. Таны утас одоо хэвийн ажиллаж байна.\n\nТа дараахыг хийсэн тохиолдолд утас тань хэт халж магадгүй:\n • Нөөц их ашигладаг аппуудыг (тоглоом, видео эсвэл навигацын аппууд) ашиглах\n • Том файлууд татах эсвэл байршуулах\n • Утсаа өндөр температурт ашиглах"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Таны төхөөрөмж хэт халсан тул хөрөхөөр унтарсан. Таны төхөөрөмж одоо хэвийн ажиллаж байна.\n\nТа дараахыг хийсэн тохиолдолд төхөөрөмж тань хэт халж магадгүй:\n • Нөөц их ашигладаг аппуудыг (тоглоом, видео эсвэл навигацын аппууд) ашиглах\n • Том файлууд татах эсвэл байршуулах\n • Төхөөрөмжөө өндөр температурт ашиглах"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Таны таблет хэт халсан тул хөрөхөөр унтарсан. Таны таблет одоо хэвийн ажиллаж байна.\n\nТа дараахыг хийсэн тохиолдолд таблет тань хэт халж магадгүй:\n • Нөөц их ашигладаг аппуудыг (тоглоом, видео эсвэл навигацын аппууд) ашиглах\n • Том файлууд татах эсвэл байршуулах\n • Таблетаа өндөр температурт ашиглах"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Утас халж байна"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Төхөөрөмж халж байна"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Таблет халж байна"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Утсыг хөрөх үед зарим онцлогийг хязгаарлана.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Төхөөрөмжийг хөрөх үед зарим онцлогийг хязгаарлана.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Таблетыг хөрөх үед зарим онцлогийг хязгаарлана.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Таны утас хөрөхөөр автоматаар оролдоно. Та утсаа ашиглах боломжтой хэвээр байх хэдий ч энэ нь удаан ажиллаж магадгүй.\n\nТаны утас хөрснийхөө дараа хэвийн ажиллана."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Таны төхөөрөмж хөрөхөөр автоматаар оролдоно. Та төхөөрөмжөө ашиглах боломжтой хэвээр байх хэдий ч энэ нь удаан ажиллаж магадгүй.\n\nТаны төхөөрөмж хөрснийхөө дараа хэвийн ажиллана."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Таны таблет хөрөхөөр автоматаар оролдоно. Та таблетаа ашиглах боломжтой хэвээр байх хэдий ч энэ нь удаан ажиллаж магадгүй.\n\nТаны таблет хөрснийхөө дараа хэвийн ажиллана."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Хурууны хээ мэдрэгч асаах/унтраах товчин дээр байдаг. Энэ нь таблетын ирмэг дээрх дууны түвшний товгор товчлуурын хажууд байх хавтгай товчлуур юм."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Хурууны хээ мэдрэгч асаах/унтраах товчин дээр байдаг. Энэ нь төхөөрөмжийн ирмэг дээрх дууны түвшний товгор товчлуурын хажууд байх хавтгай товчлуур юм."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Хурууны хээ мэдрэгч асаах/унтраах товчин дээр байдаг. Энэ нь утасны ирмэг дээрх дууны түвшний товгор товчлуурын хажууд байх хавтгай товчлуур юм."</string>
diff --git a/packages/SystemUI/res-product/values-mr/strings.xml b/packages/SystemUI/res-product/values-mr/strings.xml
index 33c3eb4..821b303 100644
--- a/packages/SystemUI/res-product/values-mr/strings.xml
+++ b/packages/SystemUI/res-product/values-mr/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"तुम्ही फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाइल काढली जाईल, त्यामुळे सर्व प्रोफाइल डेटा हटवला जाईल."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा टॅबलेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"खूप गरम झाल्यामुळे फोन बंद झाला"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"खूप गरम झाल्यामुळे डिव्हाइस बंद झाले"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"खूप गरम झाल्यामुळे टॅबलेट बंद झाला"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"तुमचा फोन आता सामान्यपणे रन होत आहे.\nअधिक माहितीसाठी टॅप करा"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"तुमचे डिव्हाइस आता सामान्यपणे रन होत आहे.\nअधिक माहितीसाठी टॅप करा"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"तुमचा टॅबलेट आता सामान्यपणे रन होत आहे.\nअधिक माहितीसाठी टॅप करा"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"तुमचा फोन खूप गरम झाला होता, म्हणून तो थंड होण्यासाठी बंद झाला आहे. तुमचा फोन आता सामान्यपणे रन होत आहे.\n\nतुम्ही पुढील गोष्टी केल्यास तुमचा फोन खूप गरम होऊ शकतो:\n •स्रोत इंटेन्सिव्ह अॅप्स वापरणे (जसे की गेमिंग, व्हिडिओ किंवा नेव्हिगेशन यांसारखी अॅप्स)\n •मोठ्या फाइल डाउनलोड किंवा अपलोड करणे\n •तुमचा फोन उच्च तापमानांमध्ये वापरणे"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"तुमचे डिव्हाइस खूप गरम झाले होते, म्हणून ते थंड होण्यासाठी बंद झाले आहे. तुमचे डिव्हाइस आता सामान्यपणे रन होत आहे.\n\nतुम्ही पुढील गोष्टी केल्यास तुमचे डिव्हाइस खूप गरम होऊ शकते:\n •स्रोत इंटेन्सिव्ह अॅप्स वापरणे (जसे की गेमिंग, व्हिडिओ किंवा नेव्हिगेशन यांसारखी अॅप्स)\n •मोठ्या फाइल डाउनलोड किंवा अपलोड करणे\n •तुमचे डिव्हाइस उच्च तापमानांमध्ये वापरणे"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"तुमचा टॅबलेट खूप गरम झाला होता, म्हणून तो थंड होण्यासाठी बंद झाला आहे. तुमचा टॅबलेट आता सामान्यपणे रन होत आहे.\n\nतुम्ही पुढील गोष्टी केल्यास तुमचा टॅबलेट खूप गरम होऊ शकतो:\n •स्रोत इंटेन्सिव्ह अॅप्स वापरणे (जसे की गेमिंग, व्हिडिओ किंवा नेव्हिगेशन यांसारखी अॅप्स)\n •मोठ्या फाइल डाउनलोड किंवा अपलोड करणे\n •तुमचा टॅबलेट उच्च तापमानांमध्ये वापरणे"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"फोन गरम होत आहे"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"डिव्हाइस गरम होत आहे"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"टॅबलेट गरम होत आहे"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"फोन थंड होईपर्यंत काही वैशिष्ट्ये मर्यादित केली आहेत.\nअधिक माहितीसाठी टॅप करा"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"डिव्हाइस थंड होईपर्यंत काही वैशिष्ट्ये मर्यादित केली आहेत.\nअधिक माहितीसाठी टॅप करा"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"टॅबलेट थंड होईपर्यंत काही वैशिष्ट्ये मर्यादित केली आहेत.\nअधिक माहितीसाठी टॅप करा"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"तुमचा फोन आपोआप थंड होण्याचा प्रयत्न करेल. तुम्ही तरीही तुमचा फोन वापरू शकता, पण तो कदाचित धीम्या गतीने रन होईल.\n\nतुमचा फोन थंड झाल्यानंतर तो सामान्यपणे काम करेल."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"तुमचे डिव्हाइस आपोआप थंड होण्याचा प्रयत्न करेल. तुम्ही तरीही तुमचे डिव्हाइस वापरू शकता, पण ते कदाचित धीम्या गतीने रन होईल.\n\nतुमचे डिव्हाइस थंड झाल्यानंतर ते सामान्यपणे काम करेल."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"तुमचा टॅबलेट आपोआप थंड होण्याचा प्रयत्न करेल. तुम्ही तरीही तुमचा टॅबलेट वापरू शकता, पण तो कदाचित धीम्या गतीने रन होईल.\n\nतुमचा टॅबलेट थंड झाल्यानंतर तो सामान्यपणे काम करेल."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"फिंगरप्रिंट सेन्सर हे पॉवर बटणावर आहे. टॅबलेटच्या कडेला वर आलेल्या व्हॉल्यूम बटणाच्या बाजूला असलेले सपाट बटण म्हणजे पॉवर बटण."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"फिंगरप्रिंट सेन्सर हे पॉवर बटणावर आहे. डिव्हाइसच्या कडेला वरती आलेल्या व्हॉल्यूम बटणाच्या बाजूला असलेले सपाट बटण म्हणजे पॉवर बटण."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"फिंगरप्रिंट सेन्सर हे पॉवर बटणावर आहे. फोनच्या कडेला वर आलेल्या व्हॉल्यूम बटणाच्या बाजूला असलेले सपाट बटण म्हणजे पॉवर बटण."</string>
diff --git a/packages/SystemUI/res-product/values-ms/strings.xml b/packages/SystemUI/res-product/values-ms/strings.xml
index e1e6976..ee10626 100644
--- a/packages/SystemUI/res-product/values-ms/strings.xml
+++ b/packages/SystemUI/res-product/values-ms/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadamkan semua data profil."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci tablet anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang gagal, anda akan diminta membuka kunci telefon anda menggunakan akaun e-mel.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon dimatikan kerana panas"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Peranti dimatikan kerana panas"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet dimatikan kerana panas"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Kini telefon anda berjalan seperti biasa.\nKetik untuk mendapatkan maklumat lanjut"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Kini peranti anda berjalan seperti biasa.\nKetik untuk mendapatkan maklumat lanjut"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Kini tablet anda berjalan seperti biasa.\nKetik untuk mendapatkan maklumat lanjut"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon anda terlalu panas, oleh yang demikian telefon itu telah dimatikan untuk menyejuk. Sekarang, telefon anda berjalan seperti biasa.\n\nTelefon anda mungkin menjadi terlalu panas jika anda:\n • Menggunakan apl intensif sumber (seperti permainan, video atau apl navigasi)\n • Memuat turun atau memuat naik fail besar\n • Menggunakan telefon anda dalam suhu tinggi"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Peranti anda terlalu panas, oleh yang demikian peranti itu telah dimatikan untuk menyejuk. Sekarang, peranti anda berjalan seperti biasa.\n\nPeranti anda mungkin menjadi terlalu panas jika anda:\n • Menggunakan apl intensif sumber (seperti permainan, video atau apl navigasi)\n • Memuat turun atau memuat naik fail besar\n • Menggunakan peranti anda dalam suhu tinggi"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablet anda terlalu panas, oleh yang demikian tablet itu telah dimatikan untuk menyejuk. Sekarang, tablet anda berjalan seperti biasa.\n\nTablet anda mungkin menjadi terlalu panas jika anda:\n • Menggunakan apl intensif sumber (seperti permainan, video atau apl navigasi)\n • Memuat turun atau memuat naik fail besar\n • Menggunakan tablet anda dalam suhu tinggi"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon semakin panas"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Peranti semakin panas"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet semakin panas"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Sesetengah ciri adalah terhad semasa telefon menyejuk.\nKetik untuk mendapatkan maklumat lanjut"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Sesetengah ciri adalah terhad semasa peranti menyejuk.\nKetik untuk mendapatkan maklumat lanjut"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Sesetengah ciri adalah terhad semasa tablet menyejuk.\nKetik untuk mendapatkan maklumat lanjut"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefon anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan telefon itu tetapi telefon tersebut mungkin berjalan lebih perlahan.\n\nSetelah telefon anda sejuk, telefon itu akan berjalan seperti biasa."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Peranti anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan peranti anda tetapi peranti tersebut mungkin berjalan lebih perlahan.\n\nSetelah peranti anda sejuk, peranti itu akan berjalan seperti biasa."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablet anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan tablet itu tetapi tablet tersebut mungkin berjalan lebih perlahan.\n\nSetelah tablet anda sejuk, tablet itu akan berjalan seperti biasa."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Penderia cap jari berada pada butang kuasa. Penderia cap jari ialah butang leper yang terletak bersebelahan butang kelantangan timbul pada bahagian tepi tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Penderia cap jari berada pada butang kuasa. Penderia cap jari ialah butang leper yang terletak bersebelahan butang kelantangan timbul pada bahagian tepi peranti."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Penderia cap jari berada pada butang kuasa. Penderia cap jari ialah butang leper yang terletak bersebelahan butang kelantangan timbul pada bahagian tepi telefon."</string>
diff --git a/packages/SystemUI/res-product/values-my/strings.xml b/packages/SystemUI/res-product/values-my/strings.xml
index 68711e8..9a61692 100644
--- a/packages/SystemUI/res-product/values-my/strings.xml
+++ b/packages/SystemUI/res-product/values-my/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ဖုန်းကို <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် မှားယွင်းစွာ လော့ခ်ဖွင့်ရန် ကြိုးစားခဲ့ပါသည်။ အလုပ်ပရိုဖိုင်ကို ဖယ်ရှားလိုက်မည်ဖြစ်ပြီး ပရိုဖိုင်ဒေတာ အားလုံးကိုလည်း ဖျက်လိုက်ပါမည်။"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ တက်ဘလက်ကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"သင်သည် သင်၏ လော့ခ်ဖွင့်ခြင်းပုံစံကို <xliff:g id="NUMBER_0">%1$d</xliff:g> ကြိမ် မှားယွင်းစွာ ဆွဲခဲ့ပါသည်။ <xliff:g id="NUMBER_1">%2$d</xliff:g> ကြိမ် ထပ်မံမှားယွင်းပြီးသည့်နောက်တွင် သင့်အီးမေးလ်အကောင့်အား အသုံးပြု၍ ဖုန်းကို လော့ခ်ဖွင့်ရန် တောင်းဆိုသွားပါမည်။\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ထပ်စမ်းကြည့်ပါ။"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"အပူရှိန်ကြောင့် ဖုန်းပိတ်သွားသည်"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"အပူရှိန်ကြောင့် စက်ပစ္စည်းပိတ်သွားသည်"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"အပူရှိန်ကြောင့် တက်ဘလက်ပိတ်သွားသည်"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"သင့်ဖုန်းသည် ယခု ပုံမှန်လုပ်ဆောင်နေပါပြီ။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"သင့်စက်ပစ္စည်းသည် ယခု ပုံမှန်လုပ်ဆောင်နေပါပြီ။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"သင့်တက်ဘလက်သည် ယခု ပုံမှန်လုပ်ဆောင်နေပါပြီ။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"သင့်ဖုန်းအလွန်ပူနေသည့်အတွက် အေးသွားစေရန် ပိတ်ထားပါသည်။ ယခုပုံမှန် လုပ်ဆောင်နေပါပြီ။\n\nအောက်ပါတို့ကိုသုံးလျှင် အလွန်ပူလာနိုင်သည်-\n • ရင်းမြစ်အထူးစိုက်ထုတ်ရသော အက်ပ်များကို သုံးခြင်း (ဂိမ်းကစားခြင်း၊ ဗီဒီယို (သို့) လမ်းညွှန်အက်ပ်များ ကဲ့သို့)\n • ကြီးမားသောဖိုင်များ ဒေါင်းလုဒ် (သို့) အပ်လုဒ်လုပ်ခြင်း\n • အပူရှိန်မြင့်သောနေရာတွင် ဖုန်းကိုသုံးခြင်း"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"သင့်စက်ပစ္စည်း အလွန်ပူနေသည့်အတွက် အေးသွားစေရန် ပိတ်ထားပါသည်။ ယခုပုံမှန် လုပ်ဆောင်နေပါပြီ။\n\nအောက်ပါတို့ကိုသုံးလျှင် အလွန်ပူလာနိုင်သည်-\n • ရင်းမြစ်အထူးစိုက်ထုတ်ရသော အက်ပ်များကို သုံးခြင်း (ဂိမ်းကစားခြင်း၊ ဗီဒီယို (သို့) လမ်းညွှန်အက်ပ်များကဲ့သို့)\n • ကြီးမားသောဖိုင်များ ဒေါင်းလုဒ် (သို့) အပ်လုဒ်လုပ်ခြင်း\n • အပူရှိန်မြင့်သောနေရာတွင် စက်ပစ္စည်းကိုသုံးခြင်း"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"သင့်တက်ဘလက်အလွန်ပူနေသည့်အတွက် အေးသွားစေရန် ပိတ်ထားပါသည်။ ယခုပုံမှန် လုပ်ဆောင်နေပါပြီ။\n\nအောက်ပါတို့ကိုသုံးလျှင် အလွန်ပူလာနိုင်သည်-\n • ရင်းမြစ်အထူးစိုက်ထုတ်ရသော အက်ပ်များကို သုံးခြင်း (ဂိမ်းကစားခြင်း၊ ဗီဒီယို (သို့) လမ်းညွှန်အက်ပ်များကဲ့သို့)\n • ကြီးမားသောဖိုင်များ ဒေါင်းလုဒ် (သို့) အပ်လုဒ်လုပ်ခြင်း\n • အပူရှိန်မြင့်သောနေရာတွင် တက်ဘလက်ကိုသုံးခြင်း"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ဖုန်း ပူနွေးလာပါပြီ"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"စက်ပစ္စည်း ပူနွေးလာပါပြီ"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"တက်ဘလက် ပူနွေးလာပါပြီ"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ဖုန်း ပြန်အေးလာစဉ် အင်္ဂါရပ်အချို့ကို ကန့်သတ်ထားပါသည်။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"စက်ပစ္စည်း ပြန်အေးလာစဉ် အင်္ဂါရပ်အချို့ကို ကန့်သတ်ထားပါသည်။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"တက်ဘလက် ပြန်အေးလာစဉ် အင်္ဂါရပ်အချို့ကို ကန့်သတ်ထားပါသည်။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"သင့်ဖုန်းသည် အလိုအလျောက် ပြန်အေးသွားပါမည်။ ဖုန်းကို အသုံးပြုနိုင်သေးသော်လည်း ပိုနှေးသွားနိုင်ပါသည်။\n\nဖုန်း အေးသွားသည့်အခါ ပုံမှန်အတိုင်း ပြန်လုပ်ဆောင်လိမ့်မည်။"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"သင့်စက်ပစ္စည်းသည် အလိုအလျောက် ပြန်အေးသွားပါမည်။ စက်ပစ္စည်းကို အသုံးပြုနိုင်သေးသော်လည်း ပိုနှေးသွားနိုင်ပါသည်။\n\nစက်ပစ္စည်း အေးသွားသည့်အခါ ပုံမှန်အတိုင်း ပြန်လုပ်ဆောင်လိမ့်မည်။"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"သင့်တက်ဘလက်သည် အလိုအလျောက် ပြန်အေးသွားပါမည်။ တက်ဘလက်ကို အသုံးပြုနိုင်သေးသော်လည်း ပိုနှေးသွားနိုင်ပါသည်။\n\nတက်ဘလက် အေးသွားသည့်အခါ ပုံမှန်အတိုင်း ပြန်လုပ်ဆောင်လိမ့်မည်။"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ တက်ဘလက်၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ စက်၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ ဖုန်း၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။"</string>
diff --git a/packages/SystemUI/res-product/values-nb/strings.xml b/packages/SystemUI/res-product/values-nb/strings.xml
index 4b16a43..533a9b8 100644
--- a/packages/SystemUI/res-product/values-nb/strings.xml
+++ b/packages/SystemUI/res-product/values-nb/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Jobbprofilen blir fjernet, og alle profildataene blir slettet."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk blir du bedt om å låse opp nettbrettet via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har tegnet opplåsingsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> nye mislykkede forsøk blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefonen ble slått av på grunn av varme"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Enheten ble slått av på grunn av varme"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Nettbrett ble slått av på grunn av varme"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefonen kjører nå som normalt.\nTrykk for å se mer informasjon"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Enheten kjører nå som normalt.\nTrykk for å se mer informasjon"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Nettbrettet kjører nå som normalt.\nTrykk for å se mer informasjon"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefonen var for varm, så den ble slått av for å kjøles ned. Den kjører nå som normalt.\n\nTelefonen kan blir for varm hvis du\n • bruker ressurskrevende apper (for eksempel spill-, video- eller navigeringsapper)\n • laster store filer opp eller ned\n • bruker den ved høy temperatur"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Enheten var for varm, så den ble slått av for å kjøles ned. Den kjører nå som normalt.\n\nEnheten kan blir for varm hvis du\n • bruker ressurskrevende apper (for eksempel spill-, video- eller navigeringsapper)\n • laster store filer opp eller ned\n • bruker den ved høy temperatur"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Nettbrettet var for varmt, så det ble slått av for å kjøles ned. Det kjører nå som normalt.\n\nNettbrettet kan blir for varmt hvis du\n • bruker ressurskrevende apper (for eksempel spill-, video- eller navigeringsapper)\n • laster store filer opp eller ned\n • bruker det ved høy temperatur"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefonen begynner å bli varm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Enheten begynner å bli varm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Nettbrett begynner å bli varmt"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Enkelte funksjoner er begrenset mens telefonen kjøles ned.\nTrykk for å se mer informasjon"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Enkelte funksjoner er begrenset mens enheten kjøles ned.\nTrykk for å se mer informasjon"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Enkelte funksjoner er begrenset mens nettbrettet kjøles ned.\nTrykk for å se mer informasjon"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefonen prøver automatisk å kjøle seg ned. Du kan fremdeles bruke den, men den kjører muligens saktere.\n\nNår telefonen har kjølt seg ned, kjører den som normalt."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Enheten prøver automatisk å kjøle seg ned. Du kan fremdeles bruke den, men den kjører muligens saktere.\n\nNår enheten har kjølt seg ned, kjører den som normalt."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Nettbrettet prøver automatisk å kjøle seg ned. Du kan fremdeles bruke det, men det kjører muligens saktere.\n\nNår nettbrettet har kjølt seg ned, kjører det som normalt."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingeravtrykkssensoren er på av/på-knappen. Det er den flate knappen ved siden av den hevede volumknappen på siden av nettbrettet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingeravtrykkssensoren er på av/på-knappen. Det er den flate knappen ved siden av den hevede volumknappen på siden av enheten."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingeravtrykkssensoren er på av/på-knappen. Det er den flate knappen ved siden av den hevede volumknappen på siden av telefonen."</string>
diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml
index 7276e23..274b72a 100644
--- a/packages/SystemUI/res-product/values-ne/strings.xml
+++ b/packages/SystemUI/res-product/values-ne/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> पटक असफल प्रयास गरेपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिने छ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> पटक असफल प्रयास गरेपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिने छ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"तातिएका कारण फोन अफ भयो"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"तातिएका कारण डिभाइस अफ भयो"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"तातिएका कारण ट्याब्लेट अफ भयो"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"तपाईंको फोन अहिले सामान्य रूपमा चलिरहेको छ।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"तपाईंको डिभाइस अहिले सामान्य रूपमा चलिरहेको छ।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"तपाईंको ट्याब्लेट अहिले सामान्य रूपमा चलिरहेको छ।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"तपाईंको फोन अत्यधिक तातेका कारण सेलाउनका लागि अफ भयो। तपाईंको फोन अहिले सामान्य रूपमा चल्दै छ।\n\nतपाईंले निम्न कुरा गर्नुभयो भने तपाईंको फोन अत्यधिक तात्न सक्छ:\n • धेरै स्रोत प्रयोग गर्ने एपहरू (गेमिङ, भिडियो वा नेभिगेसन एप जस्ता) प्रयोग गर्दा\n • ठुला फाइलहरू डाउनलोड वा अपलोड गर्दा\n • उच्च तापक्रममा फोन प्रयोग गर्दा"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"तपाईंको डिभाइस अत्यधिक तातेका कारण सेलाउनका लागि अफ भयो। तपाईंको डिभाइस अहिले सामान्य रूपमा चल्दै छ।\n\nतपाईंले निम्न कुरा गर्नुभयो भने तपाईंको डिभाइस अत्यधिक तात्न सक्छ:\n • धेरै स्रोत प्रयोग गर्ने एपहरू (गेमिङ, भिडियो वा नेभिगेसन एप जस्ता) प्रयोग गर्दा\n • ठुला फाइलहरू डाउनलोड वा अपलोड गर्दा\n •उच्च तापक्रममा डिभाइस प्रयोग गर्दा"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"तपाईंको ट्याब्लेट अत्यधिक तातेका कारण सेलाउनका लागि अफ भयो। तपाईंको ट्याब्लेट अहिले सामान्य रूपमा चल्दै छ।\n\nतपाईंले निम्न कुरा गर्नुभयो भने तपाईंको ट्याब्लेट अत्यधिक तात्न सक्छ:\n •धेरै स्रोत प्रयोग गर्ने एपहरू (गेमिङ, भिडियो वा नेभिगेसन एप जस्ता) प्रयोग गर्दा \n • ठुला फाइलहरू डाउनलोड वा अपलोड गर्दा\n • उच्च तापक्रममा ट्याब्लेट प्रयोग गर्दा"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"फोन तात्न थालेको छ"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"डिभाइस तात्न थालेको छ"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ट्याब्लेट तात्न थालेको छ"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"फोन सेलाउने क्रममा गर्दा केही सुविधाहरू उपलब्ध हुँदैनन्।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"डिभाइस सेलाउने क्रममा केही सुविधाहरू उपलब्ध हुँदैनन्।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ट्याब्लेट सेलाउने क्रममा केही सुविधाहरू उपलब्ध हुँदैनन्।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"तपाईंको फोनले स्वतः सेलाउने प्रयास गर्ने छ। तपाईं अझै पनि आफ्नो फोन प्रयोग गर्न सक्नुहुन्छ तर उक्त फोन अलि सुस्त चल्न सक्छ।\n\nसेलाइसकेपछि भने तपाईंको फोन पहिले जस्तै राम्ररी चल्न थाल्ने छ।"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"तपाईंको डिभाइसले स्वतः सेलाउने प्रयास गर्ने छ। तपाईं अझै पनि आफ्नो डिभाइस प्रयोग गर्न सक्नुहुन्छ तर उक्त डिभाइस अलि सुस्त चल्न सक्छ।\n\nसेलाइसकेपछि भने तपाईंको डिभाइस पहिले जस्तै राम्ररी चल्न थाल्ने छ।"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"तपाईंको ट्याब्लेटले स्वतः सेलाउने प्रयास गर्ने छ। तपाईं अझै पनि आफ्नो ट्याब्लेट प्रयोग गर्न सक्नुहुन्छ तर उक्त ट्याब्लेट अलि सुस्त चल्न सक्छ।\n\nसेलाइसकेपछि भने तपाईंको ट्याब्लेट पहिले जस्तै राम्ररी चल्न थाल्ने छ।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"फिंगरप्रिन्ट सेन्सर पावर बटनमा हुन्छ। यो ट्याब्लेटको किनारामा रहेको थोरै उचालिएको भोल्युम बटनको छेउमा रहेको चेप्टो बटन नै पावर बटन हो।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"फिंगरप्रिन्ट सेन्सर पावर बटनमा हुन्छ। यो डिभाइसको किनारामा रहेको थोरै उचालिएको भोल्युम बटनको छेउमा रहेको चेप्टो बटन नै पावर बटन हो।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"फिंगरप्रिन्ट सेन्सर पावर बटनमा हुन्छ। यो फोनको किनारामा रहेको थोरै उचालिएको भोल्युम बटनको छेउमा रहेको चेप्टो बटन नै पावर बटन हो।"</string>
diff --git a/packages/SystemUI/res-product/values-nl/strings.xml b/packages/SystemUI/res-product/values-nl/strings.xml
index 70cd0a4..abdc7ee 100644
--- a/packages/SystemUI/res-product/values-nl/strings.xml
+++ b/packages/SystemUI/res-product/values-nl/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt je gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefoon uitgezet wegens hitte"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Apparaat uitgezet wegens hitte"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet uitgezet wegens hitte"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Je telefoon functioneert nu weer zoals normaal.\nTik voor meer informatie"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Je apparaat functioneert nu weer zoals normaal.\nTik voor meer informatie"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Je tablet functioneert nu weer zoals normaal.\nTik voor meer informatie"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Je telefoon was te warm en is uitgezet om af te koelen. Je telefoon presteert nu weer zoals normaal.\n\nJe telefoon kan warm worden als je:\n • bronintensieve apps gebruikt (zoals game-, video-, of navigatie-apps),\n • grote bestanden up- of downloadt,\n • je telefoon gebruikt bij hoge temperaturen."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Je apparaat was te warm en is uitgezet om af te koelen. Je apparaat presteert nu weer zoals normaal.\n\nJe apparaat kan warm worden als je:\n • bronintensieve apps gebruikt (zoals game-, video-, of navigatie-apps),\n • grote bestanden up- of downloadt,\n • je apparaat gebruikt bij hoge temperaturen."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Je tablet was te warm en is uitgezet om af te koelen. Je tablet presteert nu weer zoals normaal.\n\nJe tablet kan warm worden als je:\n • bronintensieve apps gebruikt (zoals game-, video-, of navigatie-apps),\n • grote bestanden up- of downloadt,\n • je tablet gebruikt bij hoge temperaturen."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"De telefoon wordt warm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Het apparaat wordt warm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"De tablet wordt warm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt.\nTik voor meer informatie"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Bepaalde functies zijn beperkt terwijl het apparaat afkoelt.\nTik voor meer informatie"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Bepaalde functies zijn beperkt terwijl de tablet afkoelt.\nTik voor meer informatie"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Je telefoon probeert automatisch af te koelen. Je kunt je telefoon nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de telefoon is afgekoeld, werkt deze weer normaal."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Je apparaat probeert automatisch af te koelen. Je kunt je apparaat nog steeds gebruiken, maar het kan langzamer werken.\n\nZodra het apparaat is afgekoeld, werkt het weer normaal."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Je tablet probeert automatisch af te koelen. Je kunt je tablet nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de tablet is afgekoeld, werkt deze weer normaal."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Je vindt de vingerafdruksensor op de aan/uit-knop. Het is de platte knop naast de verhoogde volumeknop aan de zijkant van de tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Je vindt de vingerafdruksensor op de aan/uit-knop. Het is de platte knop naast de verhoogde volumeknop aan de zijkant van het apparaat."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Je vindt de vingerafdruksensor op de aan/uit-knop. Het is de platte knop naast de verhoogde volumeknop aan de zijkant van de telefoon."</string>
diff --git a/packages/SystemUI/res-product/values-or/strings.xml b/packages/SystemUI/res-product/values-or/strings.xml
index f3e8d2f..5d9345b 100644
--- a/packages/SystemUI/res-product/values-or/strings.xml
+++ b/packages/SystemUI/res-product/values-or/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ଆପଣ ଫୋନ୍କୁ ଅନ୍ଲକ୍ କରିବାକୁ<xliff:g id="NUMBER">%d</xliff:g>ଥର ଭୁଲ ପ୍ରୟାସ କରିଛନ୍ତି। କାର୍ଯ୍ୟ ପ୍ରୋଫାଇଲ୍ ବାହାର କରିଦିଆଯିବ, ଯାହା ଫଳରେ ସମସ୍ତ ପ୍ରୋଫାଇଲ୍ ଡାଟା ଡିଲିଟ୍ ହେବ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ଆପଣ ଆପଣଙ୍କ ଅନ୍ଲକ୍ ପାଟର୍ନକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଡ୍ର କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଆପଣଙ୍କୁ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ଆପଣଙ୍କ ଟାବ୍ଲୋଟ୍କୁ ଅନ୍ଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ଆପଣ ଆପଣଙ୍କ ଅନ୍ଲକ୍ ପାଟର୍ନକୁ <xliff:g id="NUMBER_0">%1$d</xliff:g>ଥର ଭୁଲ ଭାବେ ଡ୍ର କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଆପଣଙ୍କୁ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ଆପଣଙ୍କ ଫୋନ୍କୁ ଅନ୍ଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ଗରମ ହେବା ଯୋଗୁଁ ଫୋନଟି ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ଗରମ ହେବା ଯୋଗୁଁ ଡିଭାଇସଟି ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ଗରମ ହେବା ଯୋଗୁଁ ଟାବଲେଟଟି ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"ଆପଣଙ୍କ ଫୋନ ବର୍ତ୍ତମାନ ସ୍ୱାଭାବିକ ଭାବେ ଚାଲୁଛି।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"ଆପଣଙ୍କ ଡିଭାଇସ ବର୍ତ୍ତମାନ ସ୍ୱାଭାବିକ ଭାବେ ଚାଲୁଛି।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"ଆପଣଙ୍କ ଟାବଲେଟ ବର୍ତ୍ତମାନ ସ୍ୱାଭାବିକ ଭାବେ ଚାଲୁଛି।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ଆପଣଙ୍କ ଫୋନଟି ଅତ୍ୟଧିକ ଗରମ ଥିବା ଯୋଗୁଁ ଥଣ୍ଡା କରାଯିବାକୁ ଏହାକୁ ବନ୍ଦ କରାଯାଇଛି। ଆପଣଙ୍କ ଫୋନ ବର୍ତ୍ତମାନ ସ୍ୱାଭାବିକ ଭାବେ ଚାଲୁଛି।\n\nଆପଣଙ୍କ ଫୋନ ଅତ୍ୟଧିକ ଗରମ ହୋଇଯାଇପାରେ ଯଦି ଆପଣ:\n • ରିସୋର୍ସ-ଇଣ୍ଟେନସିଭ ଆପ୍ସ (ଯେପରି ଗେମିଂ, ଭିଡିଓ କିମ୍ବା ନେଭିଗେସନ ଆପ୍ସ) ବ୍ୟବହାର କରନ୍ତି\n • ବଡ଼ ଫାଇଲଗୁଡ଼ିକ ଡାଉନଲୋଡ କିମ୍ବା ଅପଲୋଡ କରନ୍ତି\n • ଅଧିକ ତାପମାତ୍ରାରେ ଆପଣଙ୍କ ଫୋନ ବ୍ୟବହାର କରନ୍ତି"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ଆପଣଙ୍କ ଡିଭାଇସଟି ଅତ୍ୟଧିକ ଗରମ ଥିବା ଯୋଗୁଁ ଥଣ୍ଡା କରାଯିବାକୁ ଏହାକୁ ବନ୍ଦ କରାଯାଇଛି। ଆପଣଙ୍କ ଡିଭାଇସ ବର୍ତ୍ତମାନ ସ୍ୱାଭାବିକ ଭାବେ ଚାଲୁଛି।\n\nଆପଣଙ୍କ ଡିଭାଇସ ଅତ୍ୟଧିକ ଗରମ ହୋଇଯାଇପାରେ ଯଦି ଆପଣ:\n • ରିସୋର୍ସ-ଇଣ୍ଟେନସିଭ ଆପ୍ସ (ଯେପରି ଗେମିଂ, ଭିଡିଓ କିମ୍ବା ନେଭିଗେସନ ଆପ୍ସ) ବ୍ୟବହାର କରନ୍ତି\n • ବଡ଼ ଫାଇଲଗୁଡ଼ିକ ଡାଉନଲୋଡ କିମ୍ବା ଅପଲୋଡ କରନ୍ତି\n • ଅଧିକ ତାପମାତ୍ରାରେ ଆପଣଙ୍କ ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତି"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ଆପଣଙ୍କ ଟାବଲେଟଟି ଅତ୍ୟଧିକ ଗରମ ଥିବା ଯୋଗୁଁ ଥଣ୍ଡା କରାଯିବାକୁ ଏହାକୁ ବନ୍ଦ କରାଯାଇଛି। ଆପଣଙ୍କ ଟାବଲେଟ ବର୍ତ୍ତମାନ ସ୍ୱାଭାବିକ ଭାବେ ଚାଲୁଛି।\n\nଆପଣଙ୍କ ଟାବଲେଟ ଅତ୍ୟଧିକ ଗରମ ହୋଇଯାଇପାରେ ଯଦି ଆପଣ:\n • ରିସୋର୍ସ-ଇଣ୍ଟେନସିଭ ଆପ୍ସ (ଯେପରି ଗେମିଂ, ଭିଡିଓ କିମ୍ବା ନେଭିଗେସନ ଆପ୍ସ) ବ୍ୟବହାର କରନ୍ତି\n • ବଡ଼ ଫାଇଲଗୁଡ଼ିକ ଡାଉନଲୋଡ କିମ୍ବା ଅପଲୋଡ କରନ୍ତି\n • ଅଧିକ ତାପମାତ୍ରାରେ ଆପଣଙ୍କ ଟାବଲେଟ ବ୍ୟବହାର କରନ୍ତି"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ଫୋନଟି ଗରମ ହେଉଛି"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ଡିଭାଇସଟି ଗରମ ହେଉଛି"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ଟାବଲେଟଟି ଗରମ ହେଉଛି"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ଫୋନ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର ସୀମିତ ଅଟେ।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ଡିଭାଇସ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର ସୀମିତ ଅଟେ।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ଟାବଲେଟ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର ସୀମିତ ଅଟେ।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"ଆପଣଙ୍କ ଫୋନ ସ୍ୱତଃ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ଏବେ ବି ଆପଣଙ୍କ ଫୋନ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଫୋନ ଥଣ୍ଡା ହୋଇଯିବା ପରେ ଏହା ସ୍ୱାଭାବିକ ଭାବେ ଚାଲିବ।"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"ଆପଣଙ୍କ ଡିଭାଇସ ସ୍ୱତଃ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ଏବେ ବି ଆପଣଙ୍କ ଡିଭାଇସ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଡିଭାଇସ ଥଣ୍ଡା ହୋଇଯିବା ପରେ ଏହା ସ୍ୱାଭାବିକ ଭାବେ ଚାଲିବ।"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"ଆପଣଙ୍କ ଟାବଲେଟ ସ୍ୱତଃ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ଏବେ ବି ଆପଣଙ୍କ ଟାବଲେଟ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଟାବଲେଟ ଥଣ୍ଡା ହୋଇଯିବା ପରେ ଏହା ସ୍ୱାଭାବିକ ଭାବେ ଚାଲିବ।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ଟିପଚିହ୍ନ ସେନ୍ସର ପାୱାର ବଟନରେ ଅଛି। ଏହା ଟାବଲେଟର ଧାରରେ ବଢ଼ାଯାଇଥିବା ଭଲ୍ୟୁମ ବଟନ ପାଖରେ ଥିବା ଫ୍ଲାଟ ବଟନ ଅଟେ।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ଟିପଚିହ୍ନ ସେନ୍ସର ପାୱାର ବଟନରେ ଅଛି। ଏହା ଡିଭାଇସର ଧାରରେ ବଢ଼ାଯାଇଥିବା ଭଲ୍ୟୁମ ବଟନ ପାଖରେ ଥିବା ଫ୍ଲାଟ ବଟନ ଅଟେ।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ଟିପଚିହ୍ନ ସେନ୍ସର ପାୱାର ବଟନରେ ଅଛି। ଏହା ଫୋନର ଧାରରେ ଉଠି ରହିଥିବା ଭଲ୍ୟୁମ ବଟନ ପାଖରେ ଥିବା ଫ୍ଲାଟ ବଟନ ଅଟେ।"</string>
diff --git a/packages/SystemUI/res-product/values-pa/strings.xml b/packages/SystemUI/res-product/values-pa/strings.xml
index 38fd890..81b047c 100644
--- a/packages/SystemUI/res-product/values-pa/strings.xml
+++ b/packages/SystemUI/res-product/values-pa/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗਲਤ ਢੰਗ ਨਾਲ ਫ਼ੋਨ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਹੈ। ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਨਾਲ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟ ਜਾਵੇਗਾ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਉਲੀਕਿਆ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਵੇਗਾ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"ਗਰਮ ਹੋਣ ਕਰਕੇ ਫ਼ੋਨ ਬੰਦ ਹੋ ਗਿਆ"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"ਗਰਮ ਹੋਣ ਕਰਕੇ ਡੀਵਾਈਸ ਬੰਦ ਹੋ ਗਿਆ"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ਗਰਮ ਹੋਣ ਕਰਕੇ ਟੈਬਲੈੱਟ ਬੰਦ ਹੋ ਗਿਆ"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਸੀ, ਇਸ ਲਈ ਇਹ ਠੰਡਾ ਹੋਣ ਵਾਸਤੇ ਬੰਦ ਹੋ ਗਿਆ ਸੀ। ਤੁਹਾਡਾ ਫ਼ੋਨ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\n\nਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਹੋ ਸਕਦਾ ਹੈ ਜੇ:\n • ਤੁਸੀਂ ਸਰੋਤਾਂ ਦੀ ਵੱਧ ਵਰਤੋਂ ਵਾਲੀਆਂ ਐਪਾਂ (ਜਿਵੇਂ ਗੇਮਿੰਗ, ਵੀਡੀਓ, ਜਾਂ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਐਪਾਂ) ਵਰਤਦੇ ਹੋ\n • ਵੱਡੀਆਂ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਜਾਂ ਅੱਪਲੋਡ ਕਰਦੇ ਹੋ\n • ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਉੱਚ ਤਾਪਮਾਨਾਂ ਵਿੱਚ ਵਰਤਦੇ ਹੋ"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਬਹੁਤ ਗਰਮ ਸੀ, ਇਸ ਲਈ ਇਹ ਠੰਡਾ ਹੋਣ ਵਾਸਤੇ ਬੰਦ ਹੋ ਗਿਆ ਸੀ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\n\nਤੁਹਾਡਾ ਡੀਵਾਈਸ ਬਹੁਤ ਗਰਮ ਹੋ ਸਕਦਾ ਹੈ ਜੇ:\n • ਤੁਸੀਂ ਸਰੋਤਾਂ ਦੀ ਵੱਧ ਵਰਤੋਂ ਵਾਲੀਆਂ ਐਪਾਂ (ਜਿਵੇਂ ਗੇਮਿੰਗ, ਵੀਡੀਓ, ਜਾਂ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਐਪਾਂ) ਵਰਤਦੇ ਹੋ\n • ਵੱਡੀਆਂ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਜਾਂ ਅੱਪਲੋਡ ਕਰਦੇ ਹੋ\n • ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਉੱਚ ਤਾਪਮਾਨਾਂ ਵਿੱਚ ਵਰਤਦੇ ਹੋ"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਬਹੁਤ ਗਰਮ ਸੀ, ਇਸ ਲਈ ਇਹ ਠੰਡਾ ਹੋਣ ਵਾਸਤੇ ਬੰਦ ਹੋ ਗਿਆ ਸੀ। ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\n\nਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਬਹੁਤ ਗਰਮ ਹੋ ਸਕਦਾ ਹੈ ਜੇ:\n • ਤੁਸੀਂ ਸਰੋਤਾਂ ਦੀ ਵੱਧ ਵਰਤੋਂ ਵਾਲੀਆਂ ਐਪਾਂ (ਜਿਵੇਂ ਗੇਮਿੰਗ, ਵੀਡੀਓ, ਜਾਂ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਐਪਾਂ) ਵਰਤਦੇ ਹੋ\n • ਵੱਡੀਆਂ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਜਾਂ ਅੱਪਲੋਡ ਕਰਦੇ ਹੋ\n • ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਉੱਚ ਤਾਪਮਾਨਾਂ ਵਿੱਚ ਵਰਤਦੇ ਹੋ"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ਫ਼ੋਨ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"ਡੀਵਾਈਸ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ਟੈਬਲੈੱਟ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ਫ਼ੋਨ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਤ ਹੁੰਦੀਆਂ ਹਨ।\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ਡੀਵਾਈਸ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਤ ਹੁੰਦੀਆਂ ਹਨ।\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ਟੈਬਲੈੱਟ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਤ ਹੁੰਦੀਆਂ ਹਨ।\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਆਪਣੇ-ਆਪ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ ਹੌਲੀ ਚੱਲੇ।\n\nਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਡਾ ਫ਼ੋਨ ਆਮ ਵਾਂਗ ਚੱਲੇਗਾ।"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਆਪਣੇ-ਆਪ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰ ਹੋ ਸਕਦਾ ਹੈ ਇਹ ਹੌਲੀ ਚੱਲੇ।\n\nਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਆਮ ਵਾਂਗ ਚੱਲੇਗਾ।"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਆਪਣੇ-ਆਪ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਟੈਬਲੈੱਟ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰ ਹੋ ਸਕਦਾ ਹੈ ਇਹ ਹੌਲੀ ਚੱਲੇ।\n\nਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਆਮ ਵਾਂਗ ਚੱਲੇਗਾ।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਪਾਵਰ ਬਟਨ \'ਤੇ ਹੈ। ਇਹ ਟੈਬਲੈੱਟ ਦੇ ਕਿਨਾਰੇ \'ਤੇ ਅਜਿਹਾ ਸਮਤਲ ਬਟਨ ਹੁੰਦਾ ਹੈ ਜੋ ਉੱਭਰੇ ਹੋਏ ਅਵਾਜ਼ ਬਟਨ ਦੇ ਅੱਗੇ ਹੁੰਦਾ ਹੈ।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਪਾਵਰ ਬਟਨ \'ਤੇ ਹੈ। ਇਹ ਡੀਵਾਈਸ ਦੇ ਕਿਨਾਰੇ \'ਤੇ ਅਜਿਹਾ ਸਮਤਲ ਬਟਨ ਹੁੰਦਾ ਹੈ ਜੋ ਉੱਭਰੇ ਹੋਏ ਅਵਾਜ਼ ਬਟਨ ਦੇ ਅੱਗੇ ਹੁੰਦਾ ਹੈ।"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਪਾਵਰ ਬਟਨ \'ਤੇ ਹੈ। ਇਹ ਫ਼ੋਨ ਦੇ ਕਿਨਾਰੇ \'ਤੇ ਅਜਿਹਾ ਸਮਤਲ ਬਟਨ ਹੁੰਦਾ ਹੈ ਜੋ ਉੱਭਰੇ ਹੋਏ ਅਵਾਜ਼ ਬਟਨ ਦੇ ਅੱਗੇ ਹੁੰਦਾ ਹੈ।"</string>
diff --git a/packages/SystemUI/res-product/values-pl/strings.xml b/packages/SystemUI/res-product/values-pl/strings.xml
index 7dc2ded..286a242 100644
--- a/packages/SystemUI/res-product/values-pl/strings.xml
+++ b/packages/SystemUI/res-product/values-pl/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowano nieprawidłowo odblokować telefon. Profil służbowy zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowano wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowano wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu konta e-mail.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon wyłączony: przegrzanie"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Urządzenie wyłączone: przegrzanie"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet wyłączony: przegrzanie"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefon działa teraz normalnie.\nKliknij, aby dowiedzieć się więcej"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Urządzenie działa teraz normalnie.\nKliknij, aby dowiedzieć się więcej"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tablet działa teraz normalnie.\nKliknij, aby dowiedzieć się więcej"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon był zbyt gorący i wyłączył się, aby obniżyć temperaturę. Działa teraz normalnie.\n\nTelefon może się przegrzać, gdy:\n • używasz aplikacji zużywających dużo zasobów (np. aplikacji do gier, nawigacji lub odtwarzania filmów);\n • pobierasz lub przesyłasz duże pliki;\n • używasz go w wysokiej temperaturze."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Urządzenie było zbyt gorące i wyłączyło się, aby obniżyć temperaturę. Działa teraz normalnie.\n\nUrządzenie może się przegrzać, gdy:\n • używasz aplikacji zużywających dużo zasobów (np. aplikacji do gier, nawigacji lub odtwarzania filmów);\n • pobierasz lub przesyłasz duże pliki;\n • używasz go w wysokiej temperaturze."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablet był zbyt gorący i wyłączył się, aby obniżyć temperaturę. Działa teraz normalnie.\n\nTablet może się przegrzać, gdy:\n • używasz aplikacji zużywających dużo zasobów (np. aplikacji do gier, nawigacji lub odtwarzania filmów);\n • pobierasz lub przesyłasz duże pliki;\n • używasz go w wysokiej temperaturze."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon się nagrzewa"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Urządzenie się nagrzewa"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet się nagrzewa"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone.\nKliknij, aby dowiedzieć się więcej"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Podczas obniżania temperatury urządzenia niektóre funkcje są ograniczone.\nKliknij, aby dowiedzieć się więcej"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Podczas obniżania temperatury tabletu niektóre funkcje są ograniczone.\nKliknij, aby dowiedzieć się więcej"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefon automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale może działać wolniej.\n\nGdy temperatura się obniży, telefon będzie działać normalnie."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Urządzenie automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale może działać wolniej.\n\nGdy temperatura się obniży, urządzenie będzie działać normalnie."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablet automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale może działać wolniej.\n\nGdy temperatura się obniży, tablet będzie działać normalnie."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Czytnik linii papilarnych znajduje się na przycisku zasilania. To płaski przycisk przy uniesionym przycisku głośności na krawędzi tabletu."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Czytnik linii papilarnych znajduje się na przycisku zasilania. To płaski przycisk przy uniesionym przycisku głośności na krawędzi urządzenia."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Czytnik linii papilarnych znajduje się na przycisku zasilania. To płaski przycisk przy uniesionym przycisku głośności na krawędzi telefonu."</string>
diff --git a/packages/SystemUI/res-product/values-pt-rBR/strings.xml b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
index 53efe3e..3d6d890 100644
--- a/packages/SystemUI/res-product/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rBR/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o smartphone.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Smartphone desligado por superaquecimento"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Dispositivo desligado por superaquecimento"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet desligado por superaquecimento"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"O smartphone está funcionando normalmente agora.\nToque para saber mais"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"O dispositivo está funcionando normalmente agora.\nToque para saber mais"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"O tablet está funcionando normalmente agora.\nToque para saber mais"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"O smartphone estava muito quente e foi desligado para resfriar. Agora, ele está funcionando normalmente.\n\nO smartphone pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer o download ou upload de arquivos grandes;\n • usar o smartphone em temperaturas altas."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"O dispositivo estava muito quente e foi desligado para resfriar. Agora, ele está funcionando normalmente.\n\nO dispositivo pode ficar quente demais se você:\n • usa apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • faz download ou upload de arquivos grandes;\n • usa o dispositivo em temperaturas altas."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"O tablet estava muito quente e foi desligado para resfriar. Agora, ele está funcionando normalmente.\n\nO tablet pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer download ou upload de arquivos grandes;\n • usar o tablet em temperaturas altas."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"O smartphone está esquentando"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"O dispositivo está esquentando"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"O tablet está esquentando"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Alguns recursos ficam limitados enquanto o dispositivo é resfriado.\nToque para saber mais"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Alguns recursos ficam limitados enquanto o tablet é resfriado.\nToque para saber mais"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Seu dispositivo vai tentar se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nDepois de resfriado, o dispositivo volta ao normal."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Seu tablet vai tentar se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nDepois de resfriado, o tablet volta ao normal."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do dispositivo."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do smartphone."</string>
diff --git a/packages/SystemUI/res-product/values-pt-rPT/strings.xml b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
index 29a2001..40c7e53 100644
--- a/packages/SystemUI/res-product/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-product/values-pt-rPT/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que eliminará todos os dados do mesmo."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telemóvel desligado devido ao calor"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Dispositivo desligado devido ao calor"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet desligado devido ao calor"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"O seu telemóvel já está a funcionar normalmente.\nToque para obter mais informações"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"O seu dispositivo já está a funcionar normalmente.\nToque para obter mais informações"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"O seu tablet já está a funcionar normalmente.\nToque para obter mais informações"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"O telemóvel estava muito quente, por isso desligou-se para arrefecer. Agora funciona normalmente.\n\nO telemóvel pode sobreaquecer se:\n • Usar apps que exigem mais recursos (jogos, vídeo ou apps de navegação)\n • Transferir ou carregar ficheiros grandes\n • For usado em altas temperaturas"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"O dispositivo estava muito quente, por isso desligou-se para arrefecer. Agora funciona normalmente.\n\nO dispositivo pode sobreaquecer se:\n • Usar apps que exigem mais recursos (jogos, vídeo ou apps de navegação)\n • Transferir ou carregar ficheiros grandes\n • For usado em altas temperaturas"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"O tablet estava muito quente, por isso desligou-se para arrefecer. Agora funciona normalmente.\n\nO tablet pode sobreaquecer se:\n • Usar apps que exigem mais recursos (jogos, vídeo ou apps de navegação)\n • Transferir ou carregar ficheiros grandes\n • For usado em altas temperaturas"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"O telemóvel está a aquecer"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"O dispositivo está a aquecer"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"O tablet está a aquecer"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece.\nToque para obter mais informações"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Algumas funcionalidades são limitadas enquanto o dispositivo arrefece.\nToque para obter mais informações"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Algumas funcionalidades são limitadas enquanto o tablet arrefece.\nToque para obter mais informações"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Pode continuar a usá-lo, mas este pode funcionar mais lentamente.\n\nAssim que o telemóvel tiver arrefecido, vai funcionar normalmente."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"O dispositivo vai tentar arrefecer automaticamente. Pode continuar a usá-lo, mas este pode funcionar mais lentamente.\n\nAssim que o dispositivo tiver arrefecido, vai funcionar normalmente."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"O tablet vai tentar arrefecer automaticamente. Pode continuar a usá-lo, mas este pode funcionar mais lentamente.\n\nAssim que o tablet tiver arrefecido, vai funcionar normalmente."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impressões digitais encontra-se no botão ligar/desligar. É o botão sem relevo junto ao botão de volume com relevo na extremidade do tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impressões digitais encontra-se no botão ligar/desligar. É o botão sem relevo junto ao botão de volume com relevo na extremidade do dispositivo."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impressões digitais encontra-se no botão ligar/desligar. É o botão sem relevo junto ao botão de volume com relevo na extremidade do telemóvel."</string>
diff --git a/packages/SystemUI/res-product/values-pt/strings.xml b/packages/SystemUI/res-product/values-pt/strings.xml
index 53efe3e..3d6d890 100644
--- a/packages/SystemUI/res-product/values-pt/strings.xml
+++ b/packages/SystemUI/res-product/values-pt/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. O perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o tablet.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Você desenhou seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use uma conta de e-mail para desbloquear o smartphone.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Smartphone desligado por superaquecimento"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Dispositivo desligado por superaquecimento"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet desligado por superaquecimento"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"O smartphone está funcionando normalmente agora.\nToque para saber mais"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"O dispositivo está funcionando normalmente agora.\nToque para saber mais"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"O tablet está funcionando normalmente agora.\nToque para saber mais"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"O smartphone estava muito quente e foi desligado para resfriar. Agora, ele está funcionando normalmente.\n\nO smartphone pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer o download ou upload de arquivos grandes;\n • usar o smartphone em temperaturas altas."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"O dispositivo estava muito quente e foi desligado para resfriar. Agora, ele está funcionando normalmente.\n\nO dispositivo pode ficar quente demais se você:\n • usa apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • faz download ou upload de arquivos grandes;\n • usa o dispositivo em temperaturas altas."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"O tablet estava muito quente e foi desligado para resfriar. Agora, ele está funcionando normalmente.\n\nO tablet pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer download ou upload de arquivos grandes;\n • usar o tablet em temperaturas altas."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"O smartphone está esquentando"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"O dispositivo está esquentando"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"O tablet está esquentando"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Alguns recursos ficam limitados enquanto o dispositivo é resfriado.\nToque para saber mais"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Alguns recursos ficam limitados enquanto o tablet é resfriado.\nToque para saber mais"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Seu dispositivo vai tentar se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nDepois de resfriado, o dispositivo volta ao normal."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Seu tablet vai tentar se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nDepois de resfriado, o tablet volta ao normal."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do dispositivo."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"O sensor de impressão digital fica no botão liga/desliga. Ele é plano e está ao lado do botão de volume na borda do smartphone."</string>
diff --git a/packages/SystemUI/res-product/values-ro/strings.xml b/packages/SystemUI/res-product/values-ro/strings.xml
index cd08dee..f10d5ca 100644
--- a/packages/SystemUI/res-product/values-ro/strings.xml
+++ b/packages/SystemUI/res-product/values-ro/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi tableta cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi telefonul cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefonul s-a oprit din cauza încălzirii"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Dispozitiv oprit din cauza căldurii"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tableta s-a oprit din cauza încălzirii"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Acum telefonul funcționează normal.\nAtinge pentru mai multe informații"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Acum dispozitivul funcționează normal.\nAtinge pentru mai multe informații"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Acum tableta funcționează normal.\nAtinge pentru mai multe informații"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefonul se încălzise prea mult și s-a oprit pentru a se răci. Acum funcționează normal.\n\nTelefonul s-ar putea încălzi prea mult dacă:\n • folosești aplicații care consumă multe resurse (de ex., jocuri, aplicații video sau de navigare);\n • descarci sau încarci fișiere mari;\n • folosești telefonul la temperaturi ridicate."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Dispozitivul se încălzise prea mult și s-a oprit pentru a se răci. Acum funcționează normal.\n\nDispozitivul s-ar putea încălzi prea mult dacă:\n • folosești aplicații care consumă multe resurse (de ex., jocuri, aplicații video sau de navigare);\n • descarci sau încarci fișiere mari;\n • folosești dispozitivul la temperaturi ridicate."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tableta se încălzise prea mult și s-a oprit pentru a se răci. Acum funcționează normal.\n\nTableta s-ar putea încălzi prea mult dacă:\n • folosești aplicații care consumă multe resurse (de ex., jocuri, aplicații video sau de navigare);\n • descarci sau încarci fișiere mari;\n • folosești tableta la temperaturi ridicate."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefonul se încălzește"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Dispozitivul se încălzește"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tableta se încălzește"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Anumite funcții sunt limitate în timp ce telefonul se răcește.\nAtinge pentru mai multe informații"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Anumite funcții sunt limitate în timp ce dispozitivul se răcește.\nAtinge pentru mai multe informații"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Anumite funcții sunt limitate în timp ce tableta se răcește.\nAtinge pentru mai multe informații"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefonul va încerca automat să se răcească. Îl poți folosi în continuare, dar e posibil să funcționeze mai lent.\n\nDupă ce se răcește, telefonul va funcționa normal."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Dispozitivul va încerca automat să se răcească. Îl poți folosi în continuare, dar e posibil să funcționeze mai lent.\n\nDupă ce se răcește, dispozitivul va funcționa normal."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tableta va încerca automat să se răcească. O poți folosi în continuare, dar e posibil să funcționeze mai lent.\n\nDupă ce se răcește, tableta va funcționa normal."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzorul de amprentă se află pe butonul de pornire. Este butonul plat de lângă butonul de volum în relief de pe marginea tabletei."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzorul de amprentă se află pe butonul de pornire. Este butonul plat de lângă butonul de volum în relief de pe marginea dispozitivului."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzorul de amprentă se află pe butonul de pornire. Este butonul plat de lângă butonul de volum în relief de pe marginea telefonului."</string>
diff --git a/packages/SystemUI/res-product/values-ru/strings.xml b/packages/SystemUI/res-product/values-ru/strings.xml
index 1649c02..ed9ad1a 100644
--- a/packages/SystemUI/res-product/values-ru/strings.xml
+++ b/packages/SystemUI/res-product/values-ru/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Вы несколько раз (<xliff:g id="NUMBER">%d</xliff:g>) не смогли разблокировать телефон. Рабочий профиль и все его данные будут удалены."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Вы несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>) ввели неверный графический ключ. Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать планшет с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Вы несколько раз (<xliff:g id="NUMBER_0">%1$d</xliff:g>) ввели неверный графический ключ. Осталось попыток: <xliff:g id="NUMBER_1">%2$d</xliff:g>. В случае неудачи вам будет предложено разблокировать телефон с помощью аккаунта электронной почты.\n\nПовторите попытку через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Телефон выключился из-за перегрева"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Устройство выключилось из-за перегрева"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Планшет выключился из-за перегрева"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Сейчас телефон работает нормально.\nНажмите, чтобы получить дополнительную информацию."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Сейчас устройство работает нормально.\nНажмите, чтобы получить дополнительную информацию."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Сейчас планшет работает нормально.\nНажмите, чтобы получить дополнительную информацию."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Телефон выключился из-за перегрева. Сейчас он работает нормально.\n\nВозможные причины перегрева:\n • использование ресурсоемких игр и приложений, например связанных с видео или навигацией;\n • скачивание или загрузка больших файлов;\n • высокая температура окружающей среды."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Устройство выключилось из-за перегрева. Сейчас оно работает нормально.\n\nВозможные причины перегрева:\n • использование ресурсоемких игр и приложений, например связанных с видео или навигацией;\n • скачивание или загрузка больших файлов;\n • высокая температура окружающей среды."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Планшет выключился из-за перегрева. Сейчас он работает нормально.\n\nВозможные причины перегрева:\n • использование ресурсоемких игр и приложений, например связанных с видео или навигацией;\n • скачивание или загрузка больших файлов;\n • высокая температура окружающей среды."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Телефон нагревается"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Устройство нагревается"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Планшет нагревается"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Пока телефон не остынет, некоторые функции могут быть недоступны.\nНажмите, чтобы получить дополнительную информацию."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Пока устройство не остынет, некоторые функции могут быть недоступны.\nНажмите, чтобы получить дополнительную информацию."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Пока планшет не остынет, некоторые функции могут быть недоступны.\nНажмите, чтобы получить дополнительную информацию."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Телефон автоматически попробует снизить температуру. Вы можете продолжать им пользоваться, но его производительность, возможно, уменьшится.\n\nСкорость работы телефона восстановится, когда он остынет."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Устройство автоматически попробует снизить температуру. Вы можете продолжать им пользоваться, но его производительность, возможно, уменьшится.\n\nСкорость работы устройства восстановится, когда оно остынет."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Планшет автоматически попробует снизить температуру. Вы можете продолжать им пользоваться, но его производительность, возможно, уменьшится.\n\nСкорость работы планшета восстановится, когда он остынет."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сканер отпечатков пальцев находится на кнопке питания. Она плоская и расположена рядом с приподнятой кнопкой регулировки громкости на боковой стороне планшета."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сканер отпечатков пальцев находится на кнопке питания. Она плоская и расположена рядом с приподнятой кнопкой регулировки громкости на боковой стороне устройства."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сканер отпечатков пальцев находится на кнопке питания. Она плоская и расположена рядом с приподнятой кнопкой регулировки громкости на боковой стороне телефона."</string>
diff --git a/packages/SystemUI/res-product/values-si/strings.xml b/packages/SystemUI/res-product/values-si/strings.xml
index 4ab2a4b..f2c0f43 100644
--- a/packages/SystemUI/res-product/values-si/strings.xml
+++ b/packages/SystemUI/res-product/values-si/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"ඔබ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදියට උත්සාහ කර ඇත. කාර්යාල පැතිකඩ ඉවත් කරනු ඇති අතර, එය සියලු පැතිකඩ දත්ත මකනු ඇත."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%2$d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> කින් උත්සාහ කරන්න."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"දුරකථනය රත් වීම නිසා ක්රියාවිරහිත විය"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"උණුසුම හේතුවෙන් උපාංගය ක්රියාවිරහිත විය"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"ටැබ්ලටය රත් වීම නිසා ක්රියාවිරහිත විය"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"ඔබේ දුරකථනය දැන් සාමාන්ය ලෙස ධාවනය වේ.\nතව තතු සඳහා තට්ටු කරන්න"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"ඔබේ උපාංගය දැන් සාමාන්ය ලෙස ධාවනය වේ.\nතව තතු සඳහා තට්ටු කරන්න"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"ඔබේ ටැබ්ලටය දැන් සාමාන්ය ලෙස ධාවනය වේ.\nතව තතු සඳහා තට්ටු කරන්න"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"ඔබේ දුරකථනය ඉතාම උණුසුම් විය, එම නිසා එය සිසිල් වීමට ක්රියාවිරහිත කරන ලදි. දැන් ඔබේ දුරකථනය සාමාන්ය පරිදි ධාවනය වේ.\n\nඔබ පහත දේවල් සිදු කළහොත් ඔබේ දුරකථනය ඉතාම උණුසුම් විය හැක:\n • සම්පත්-දැඩි සත්කාරක යෙදුම් භාවිතය (ක්රීඩා, වීඩියෝ, හෝ සංචලන යෙදුම් යනාදී)\n • විශාල ගොනු බාගැනීම හෝ උඩුගත කිරීම\n • ඔබේ දුරකථනය අධික උෂ්ණත්වයේදී භාවිත කිරීම"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"ඔබේ උපාංගය ඉතාම උණුසුම් විය, එම නිසා එය සිසිල් වීමට ක්රියාවිරහිත කරන ලදි. දැන් ඔබේ දුරකථනය සාමාන්ය පරිදි ධාවනය වේ.\n\nඔබ පහත දේවල් සිදු කළහොත් ඔබේ උපාංගය ඉතාම උණුසුම් විය හැක:\n • සම්පත්-දැඩි සත්කාරක යෙදුම් භාවිතය (ක්රීඩා, වීඩියෝ, හෝ සංචලන යෙදුම් යනාදී)\n • විශාල ගොනු බාගැනීම හෝ උඩුගත කිරීම\n • ඔබේ දුරකථනය අධික උෂ්ණත්වයේ දී භාවිත කිරීම"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"ඔබේ ටැබ්ලටය ඉතාම උණුසුම් විය, එම නිසා එය සිසිල් වීමට ක්රියාවිරහිත කරන ලදි. දැන් ඔබේ දුරකථනය සාමාන්ය පරිදි ධාවනය වේ.\n\nඔබ පහත දේවල් සිදු කළහොත් ඔබේ දුරකථනය ඉතාම උණුසුම් විය හැක:\n • සම්පත්-දැඩි සත්කාරක යෙදුම් භාවිතය (ක්රීඩා, වීඩියෝ, හෝ සංචලන යෙදුම් යනාදී)\n • විශාල ගොනු බාගැනීම හෝ උඩුගත කිරීම\n • ඔබේ දුරකථනය අධික උෂ්ණත්වයේ දී භාවිත කිරීම"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"දුරකථනය උණුසුම් වෙමින්"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"උපාංගය උණුසුම් වෙමින් පවතී"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ටැබ්ලටය උණුසුම් වෙමින් පවතී"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"දුරකථනය සිසිල් වන අතරේ සමහර විශේෂාංග සීමිත විය හැක.\nතව තතු සඳහා තට්ටු කරන්න"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"උපාංගය සිසිල් වන අතරේ සමහර විශේෂාංග සීමිත විය හැක.\nතව තතු සඳහා තට්ටු කරන්න"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ටැබ්ලටය සිසිල් වන අතරේ සමහර විශේෂාංග සීමිත විය හැක.\nතව තතු සඳහා තට්ටු කරන්න"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"ඔ බේ දුරකථනය ස්වයංක්රීයව සිසිල් වීමට උත්සාහ කරනු ඇත. ඔබට තවම ඔබේ දුරකථනය භාවිත කළ හැකි නමුත්, එය සෙමින් ධාවනය විය හැක.\n\nඔබේ දුරකථනය සිසිල් වූ පසු, එය සාමාන්ය ලෙස ධාවනය වනු ඇත."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"ඔබේ උපාංගය ස්වයංක්රීයව සිසිල් වීමට උත්සාහ දරනු ඇත. ඔබට තවමත් බබේ උපාංගය භාවිතා කළ හැකි නමුත්, එය මන්දගාමීව ධාවනය විය හැක.\n\nඔබේ උපාංගය සිසිල් වූ පසු, එය සාමාන්ය පරිදි ධාවනය වනු ඇත."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"ඔබේ ටැබ්ලටය ස්වයංක්රීයව සිසිල් වීමට උත්සාහ දරනු ඇත. ඔබට තවමත් බබේ ටැබ්ලටය භාවිතා කළ හැකි නමුත්, එය මන්දගාමීව ධාවනය විය හැක.\n\nඔබේ ටැබ්ලටය සිසිල් වූ පසු, එය සාමාන්ය පරිදි ධාවනය වනු ඇත."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"ඇඟිලි සලකුණු සංවේදකය බල බොත්තම මත ඇත. එය ටැබ්ලටයෙහි කෙළවර ඇති ඉහළ හඬ පරිමා බොත්තම අසල ඇති පැතලි බොත්තමයි."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"ඇඟිලි සලකුණු සංවේදකය බල බොත්තම මත ඇත. එය උපාංගයෙහි කෙළවර ඇති ඉහළ හඬ පරිමා බොත්තම අසල ඇති පැතලි බොත්තමයි."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"ඇඟිලි සලකුණු සංවේදකය බල බොත්තම මත ඇත. එය දුරකථනයෙහි කෙළවර ඇති ඉහළ හඬ පරිමා බොත්තම අසල ඇති පැතලි බොත්තමයි."</string>
diff --git a/packages/SystemUI/res-product/values-sk/strings.xml b/packages/SystemUI/res-product/values-sk/strings.xml
index 21bcc2a..8e1bb39 100644
--- a/packages/SystemUI/res-product/values-sk/strings.xml
+++ b/packages/SystemUI/res-product/values-sk/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>‑krát nesprávne odomknúť. Pracovný profil bude odstránený spolu so všetkými údajmi."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g>‑krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e‑mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Už ste <xliff:g id="NUMBER_0">%1$d</xliff:g>‑krát nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e‑mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefón sa vypol z dôvodu prehriatia"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Zariadenie sa vyplo z dôvodu prehriatia"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet sa vypol z dôvodu prehriatia"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Teraz telefón funguje ako obvykle.\nViac sa dozviete po klepnutí."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Teraz zariadenie funguje ako obvykle.\nViac sa dozviete po klepnutí."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Teraz tablet funguje ako obvykle.\nViac sa dozviete po klepnutí."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefón bol príliš horúci, preto sa vypol, aby vychladol. Teraz funguje ako obvykle.\n\nTelefón sa môže prehrievať, keď:\n • používate aplikácie náročné na zdroje (ako sú aplikácie na video alebo herné či navigačné),\n • sťahujete alebo nahrávate veľké súbory,\n • používate telefón pri vysokých teplotách."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Zariadenie bolo príliš horúce, preto sa vyplo, aby vychladlo. Teraz funguje ako obvykle.\n\nZariadenie sa môže prehrievať, keď:\n • používate aplikácie náročné na zdroje (ako sú aplikácie na video alebo herné či navigačné),\n • sťahujete alebo nahrávate veľké súbory,\n • používate zariadenie pri vysokých teplotách."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablet bol príliš horúci, preto sa vypol, aby vychladol. Teraz funguje ako obvykle.\n\nTablet sa môže prehrievať, keď:\n • používate aplikácie náročné na zdroje (ako sú aplikácie na video alebo herné či navigačné),\n • sťahujete alebo nahrávate veľké súbory,\n • používate tablet pri vysokých teplotách."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefón sa prehrieva"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Zariadenie sa prehrieva"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet sa prehrieva"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu.\nViac sa dozviete po klepnutí."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Niektoré funkcie budú obmedzené, dokým neklesne teplota zariadenia.\nViac sa dozviete po klepnutí."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Niektoré funkcie budú obmedzené, dokým neklesne teplota tabletu.\nViac sa dozviete po klepnutí."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Váš telefón sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude fungovať ako obvykle."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Vaše zariadenie sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude fungovať ako obvykle."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Váš tablet sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude fungovať ako obvykle."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Senzor odtlačkov prstov je na vypínači. Je to ploché tlačidlo vedľa vypuklého tlačidla hlasitosti na okraji tabletu."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Senzor odtlačkov prstov je na vypínači. Je to ploché tlačidlo vedľa vypuklého tlačidla hlasitosti na okraji zariadenia."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Senzor odtlačkov prstov je na vypínači. Je to ploché tlačidlo vedľa vypuklého tlačidla hlasitosti na okraji telefónu."</string>
diff --git a/packages/SystemUI/res-product/values-sl/strings.xml b/packages/SystemUI/res-product/values-sl/strings.xml
index 95191a4..04c7bc7 100644
--- a/packages/SystemUI/res-product/values-sl/strings.xml
+++ b/packages/SystemUI/res-product/values-sl/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen in vsi podatki profila bodo izbrisani."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Če ga neuspešno poskusite vnesti še <xliff:g id="NUMBER_1">%2$d</xliff:g>-krat, boste pozvani, da telefon odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon se je izklopil zaradi vročine"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Naprava se je izklopila zaradi vročine"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablični računalnik se je izklopil zaradi vročine"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefon zdaj deluje kot običajno.\nDotaknite se za več informacij"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Naprava zdaj deluje kot običajno.\nDotaknite se za več informacij"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tablični računalnik zdaj deluje kot običajno.\nDotaknite se za več informacij"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon je bil prevroč, zato se je izklopil, da se ohladi. Zdaj deluje kot običajno.\n\nTelefon lahko postane prevroč pri:\n • uporabi aplikacij, ki intenzivno porabljajo sredstva (npr. za igranje iger, videoposnetke ali navigacijo);\n • prenosu ali nalaganju velikih datotek;\n • uporabi naprave pri visokih temperaturah."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Naprava je bila prevroča, zato se je izklopila, da se ohladi. Zdaj deluje kot običajno.\n\nNaprava lahko postane prevroča pri:\n • uporabi aplikacij, ki intenzivno porabljajo sredstva (npr. za igranje iger, videoposnetke ali navigacijo);\n • prenosu ali nalaganju velikih datotek;\n • uporabi naprave pri visokih temperaturah."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tablični računalnik je bil prevroč, zato se je izklopil, da se ohladi. Zdaj deluje kot običajno.\n\nTablični računalnik lahko postane prevroč pri:\n • uporabi aplikacij, ki intenzivno porabljajo sredstva (npr. za igranje iger, videoposnetke ali navigacijo);\n • prenosu ali nalaganju velikih datotek;\n • uporabi naprave pri visokih temperaturah."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon se segreva"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Naprava se segreva"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablični računalnik se segreva"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Nekatere funkcije bodo med ohlajanjem telefona omejene.\nDotaknite se za več informacij"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Nekatere funkcije bodo med ohlajanjem naprave omejene.\nDotaknite se za več informacij"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Nekatere funkcije bodo med ohlajanjem tabličnega računalnika omejene.\nDotaknite se za več informacij"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefon se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se bo telefon ohladil, bo znova deloval kot običajno."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Naprava se bo samodejno poskusila ohladiti. Še naprej jo lahko uporabljate, vendar bo morda delovala počasneje.\n\nKo se bo naprava ohladila, bo znova delovala kot običajno."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tablični računalnik se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se bo tablični računalnik ohladil, bo znova deloval kot običajno."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Tipalo prstnih odtisov je na gumbu za vklop. To je ploski gumb ob izbočenem gumbu za glasnost na robu tabličnega računalnika."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Tipalo prstnih odtisov je na gumbu za vklop. To je ploski gumb ob izbočenem gumbu za glasnost na robu naprave."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Tipalo prstnih odtisov je na gumbu za vklop. To je ploski gumb ob izbočenem gumbu za glasnost na robu telefona."</string>
diff --git a/packages/SystemUI/res-product/values-sq/strings.xml b/packages/SystemUI/res-product/values-sq/strings.xml
index 435966eb..619f22f 100644
--- a/packages/SystemUI/res-product/values-sq/strings.xml
+++ b/packages/SystemUI/res-product/values-sq/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Profili i punës do të hiqet, gjë që do të fshijë të gjitha të dhënat e profilit."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd të shkyçjes. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh tabletin duke përdorur një llogari email-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari email-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefoni u fik për shkak të nxehtësisë"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Pajisja u fik për shkak të nxehtësisë"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tableti u fik për shkak të nxehtësisë"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefoni tani po funksionon normalisht.\nTrokit për më shumë informacione"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Pajisja tani po funksionon normalisht.\nTrokit për më shumë informacione"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tableti tani po funksionon normalisht.\nTrokit për më shumë informacione"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefoni yt ishte shumë i nxehtë, prandaj u fik për t\'u ftohur. Telefoni tani po funksionon normalisht.\n\nTelefoni yt mund të nxehet shumë nëse ti:\n • Përdor aplikacione intensive për burimet (si p.sh. aplikacione lojërash, videosh ose navigimi)\n • Shkarkon ose ngarkon skedarë të mëdhenj\n • Përdor telefonin në temperatura të larta"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Pajisja jote ishte shumë e nxehtë, prandaj u fik për t\'u ftohur. Pajisja tani po funksionon normalisht.\n\nPajisja jote mund të nxehet shumë nëse ti:\n • Përdor aplikacione intensive për burimet (si p.sh. aplikacione lojërash, videosh ose navigimi)\n • Shkarkon ose ngarkon skedarë të mëdhenj\n • Përdor pajisjen në temperatura të larta"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tableti yt ishte shumë i nxehtë, prandaj u fik për t\'u ftohur. Tableti tani po funksionon normalisht.\n\nTableti yt mund të nxehet shumë nëse ti:\n • Përdor aplikacione intensive për burimet (si p.sh. aplikacione lojërash, videosh ose navigimi)\n • Shkarkon ose ngarkon skedarë të mëdhenj\n • Përdor tabletin në temperatura të larta"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefoni po nxehet"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Pajisja po nxehet"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tableti po nxehet"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Disa veçori janë të kufizuara ndërkohë që telefoni ftohet.\nTrokit për më shumë informacione"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Disa veçori janë të kufizuara ndërkohë që pajisja ftohet.\nTrokit për më shumë informacione"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Disa veçori janë të kufizuara ndërkohë që telefoni ftohet.\nTrokit për më shumë informacione"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefoni yt do të përpiqet automatikisht të ftohet. Mund të vazhdosh ta përdorësh telefonin, por ai mund të funksionojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të funksionojë normalisht."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Pajisja jote do të përpiqet automatikisht të ftohet. Mund të vazhdosh ta përdorësh pajisjen, por ajo mund të funksionojë më ngadalë.\n\nPasi pajisja të jetë ftohur, ajo do të funksionojë normalisht."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tableti yt do të përpiqet automatikisht të ftohet. Mund të vazhdosh ta përdorësh tabletin, por ai mund të funksionojë më ngadalë.\n\nPasi tableti të jetë ftohur, ai do të funksionojë normalisht."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Sensori i gjurmës së gishtit është në butonin e energjisë. Ai është butoni i rrafshët pranë butonit të ngritur të volumit në anë të tabletit."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Sensori i gjurmës së gishtit është në butonin e energjisë. Ai është butoni i rrafshët pranë butonit të ngritur të volumit në anë të pajisjes."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Sensori i gjurmës së gishtit është në butonin e energjisë. Ai është butoni i rrafshët pranë butonit të ngritur të volumit në anë të telefonit."</string>
diff --git a/packages/SystemUI/res-product/values-sr/strings.xml b/packages/SystemUI/res-product/values-sr/strings.xml
index 4c458a4..76cd9ed 100644
--- a/packages/SystemUI/res-product/values-sr/strings.xml
+++ b/packages/SystemUI/res-product/values-sr/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Уклонићемо пословни профил, чиме се бришу сви подаци са профила."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате таблет помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Нетачно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Ако погрешно покушате још <xliff:g id="NUMBER_1">%2$d</xliff:g> пута, затражићемо да откључате телефон помоћу имејл налога.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Телефон се искључио због топлоте"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Уређај се искључио због топлоте"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Таблет се искључио због топлоте"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Телефон сада функционише нормално.\nДодирните за више информација"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Уређај сада функционише нормално.\nДодирните за више информација"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Таблет сада функционише нормално.\nДодирните за више информација"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Телефон је био преврућ, па се искључио да се охлади. Сада ради нормално.\n\nТелефон може превише да се угреје ако:\n • користите апликације које захтевају пуно ресурса (нпр. видео игре, видео или апликације за навигацију)\n • преузимате или отпремате велике фајлове\n • користите телефон на високој температури"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Уређај је био преврућ, па се искључио да се охлади. Сада ради нормално.\n\nУређај може превише да се угреје ако:\n • користите апликације које захтевају пуно ресурса (нпр. видео игре, видео или апликације за навигацију)\n • преузимате или отпремате велике фајлове\n • користите уређај на високој температури"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Таблет је био преврућ, па се искључио да се охлади. Сада ради нормално.\n\nТаблет може превише да се угреје ако:\n • користите апликације које захтевају пуно ресурса (нпр. видео игре, видео или апликације за навигацију)\n • преузимате или отпремате велике фајлове\n • користите таблет на високој температури"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Телефон се загрејао"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Уређај се загрејао"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Таблет се загрејао"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Неке функције су ограничене док се телефон не охлади.\nДодирните за више информација"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Неке функције су ограничене док се уређај не охлади.\nДодирните за више информација"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Неке функције су ограничене док се таблет не охлади.\nДодирните за више информација"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Телефон ће аутоматски покушати да се охлади. И даље можете да користите телефон, али ће можда радити спорије.\n\nКад се телефон охлади, функционисаће нормално."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Уређај ће аутоматски покушати да се охлади. И даље можете да користите уређај, али ће можда радити спорије.\n\nКад се уређај охлади, функционисаће нормално."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Таблет ће аутоматски покушати да се охлади. И даље можете да користите таблет, али ће можда радити спорије.\n\nКад се таблет охлади, функционисаће нормално."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сензор за отисак прста се налази на дугмету за укључивање. То је равно дугме поред издигнутог дугмета за јачину звука на ивици таблета."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сензор за отисак прста се налази на дугмету за укључивање. То је равно дугме поред издигнутог дугмета за јачину звука на ивици уређаја."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сензор за отисак прста се налази на дугмету за укључивање. То је равно дугме поред издигнутог дугмета за јачину звука на ивици телефона."</string>
diff --git a/packages/SystemUI/res-product/values-sv/strings.xml b/packages/SystemUI/res-product/values-sv/strings.xml
index e2bbfa1..bb97e5c 100644
--- a/packages/SystemUI/res-product/values-sv/strings.xml
+++ b/packages/SystemUI/res-product/values-sv/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Du har försökt låsa upp telefonen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Jobbprofilen tas bort och all profildata raderas."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp surfplattan med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök måste du låsa upp telefonen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefonen stängdes av p.g.a. värme"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Enheten stängdes av p.g.a. värme"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Surfplattan stängdes av p.g.a. värme"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefonen fungerar nu som vanligt.\nTryck för mer information"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Enheten fungerar nu som vanligt.\nTryck för mer information"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Surfplattan fungerar nu som vanligt.\nTryck för mer information"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefonen var för varm och stängdes av för att svalna. Den fungerar nu som vanligt.\n\nTelefonen kan bli för varm om du\n • använder resurskrävande appar (till exempel spel-, video- eller navigeringsappar)\n • laddar ned eller laddar upp stora filer\n • använder telefonen vid höga temperaturer."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Enheten var för varm och stängdes av för att svalna. Den fungerar nu som vanligt.\n\nEnheten kan bli för varm om du\n • använder resurskrävande appar (till exempel spel-, video- eller navigeringsappar)\n • laddar ned eller laddar upp stora filer\n • använder enheten vid höga temperaturer."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Surfplattan var för varm och stängdes av för att svalna. Den fungerar nu som vanligt.\n\nSurfplattan kan bli för varm om du\n • använder resurskrävande appar (till exempel spel-, video- eller navigeringsappar)\n • laddar ned eller laddar upp stora filer\n • använder surfplattan vid höga temperaturer."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefonen börjar bli varm"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Enheten börjar bli varm"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Surfplattan börjar bli varm"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Vissa funktioner är begränsade medan telefonen svalnar.\nTryck för mer information"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Vissa funktioner är begränsade medan enheten svalnar.\nTryck för mer information"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Vissa funktioner är begränsade medan surfplattan svalnar.\nTryck för mer information"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefonen försöker svalna automatiskt. Du kan fortfarande använda telefonen, men den kan vara långsammare än vanligt.\n\nTelefonen fungerar som vanligt när den har svalnat."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Enheten försöker svalna automatiskt. Du kan fortfarande använda enheten, men den kan vara långsammare än vanligt.\n\nEnheten fungerar som vanligt när den har svalnat."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Surfplattan försöker svalna automatiskt. Du kan fortfarande använda surfplattan, men den kan vara långsammare än vanligt.\n\nSurfplattan fungerar som vanligt när den har svalnat."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Fingeravtryckssensorn sitter på av/på-knappen. Det är den platta knappen bredvid den upphöjda volymknappen på surfplattans kant."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Fingeravtryckssensorn sitter på av/på-knappen. Det är den platta knappen bredvid den upphöjda volymknappen på enhetens kant."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Fingeravtryckssensorn sitter på av/på-knappen. Det är den platta knappen bredvid den upphöjda volymknappen på telefonens kant."</string>
diff --git a/packages/SystemUI/res-product/values-sw/strings.xml b/packages/SystemUI/res-product/values-sw/strings.xml
index 2ebc3eb..44e95de 100644
--- a/packages/SystemUI/res-product/values-sw/strings.xml
+++ b/packages/SystemUI/res-product/values-sw/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Umejaribu kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g> bila mafanikio. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Umeweka mchoro usio sahihi wa kufungua skrini mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi bila mafanikio, utaombwa ufungue kompyuta yako kibao kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Umeweka mchoro usio sahihi wa kufungua skrini mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea mara nyingine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa ufungue simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Simu imezimika kwa sababu ya joto"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Kifaa kimezimika kwa sababu ya joto"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Kishikwambi kimezimika kutokana na joto"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Simu yako sasa inafanya kazi inavyostahili.\nGusa ili upate maelezo zaidi"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Kifaa chako sasa kinafanya kazi inavyostahili.\nGusa ili upate maelezo zaidi"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Kishikwambi chako sasa kinafanya kazi inavyostahili.\nGusa ili upate maelezo zaidi"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Simu yako ilikuwa na joto jingi mno, kwa hivyo imezimika ili ipoe. Simu yako sasa inafanya kazi inavyostahili.\n\nHuenda simu yako ikawa na joto jingi mno:\n • Ukitumia programu zinazoendesha nyenzo nyingi (kama vile michezo ya video, video au programu za uelekezaji)\n • Ukipakua au ukipakia faili kubwa\n • Ukitumia simu mahali palipo na joto jingi"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Kifaa chako kilikuwa na joto jingi mno, kwa hivyo kimezimika ili kipoe. Kifaa chako sasa kinafanya kazi inavyostahili.\n\nHuenda kifaa chako kikawa na joto jingi mno:\n • Ukitumia programu zinazoendesha nyenzo nyingi (kama vile michezo ya video, video au programu za uelekezaji)\n • Ukipakua au ukipakia faili kubwa\n • Ukitumia kifaa mahali palipo na joto jingi"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Kishikwambi chako kilikuwa na joto jingi mno, kwa hivyo kimezimika ili kipoe. Kishikwambi chako sasa kinafanya kazi inavyostahili.\n\nHuenda kishikwambi chako kikawa na joto jingi mno:\n • Ukitumia programu zinazoendesha nyenzo nyingi (kama vile michezo ya video, video au programu za uelekezaji)\n • Ukipakua au ukipakia faili kubwa\n • Ukitumia kishikwambi mahali palipo na joto jingi"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Simu inapata joto"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Kifaa kinapata joto"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Kishikwambi kinapata joto"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Huenda usiweze kutumia baadhi ya vipengele wakati simu inapoa.\nGusa ili upate maelezo zaidi"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Huenda usiweze kutumia baadhi ya vipengele wakati kifaa kinapoa.\nGusa ili upate maelezo zaidi"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Huenda usiweze kutumia baadhi ya vipengele wakati kishikwambi kinapoa.\nGusa ili upate maelezo zaidi"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Simu yako itajaribu kupoa kiotomatiki. Bado unaweza kutumia simu yako, lakini huenda ikafanya kazi polepole.\n\nSimu yako ikipoa, itaendelea kufanya kazi inavyostahili."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Kifaa chako kitajaribu kupoa kiotomatiki. Bado unaweza kutumia kifaa chako, lakini huenda kikafanya kazi polepole.\n\nKifaa chako kikipoa, kitaendelea kufanya kazi inavyostahili."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Kishikwambi chako kitajaribu kupoa kiotomatiki. Bado unaweza kutumia kishikwambi chako, lakini huenda kikafanya kazi polepole.\n\nKishikwambi chako kikipoa, kitaendelea kufanya kazi inavyostahili."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Kitambuzi cha alama ya kidole kinapatikana kwenye kitufe cha kuwasha/kuzima. Ni kitufe bapa pembeni pa kitufe cha sauti kilichoinuka kwenye ukingo wa kompyuta kibao."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Kitambuzi cha alama ya kidole kinapatikana kwenye kitufe cha kuwasha/kuzima. Ni kitufe bapa pembeni pa kitufe cha sauti kilichoinuka kwenye ukingo wa kifaa."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Kitambuzi cha alama ya kidole kinapatikana kwenye kitufe cha kuwasha/kuzima. Ni kitufe bapa pembeni pa kitufe cha sauti kilichoinuka kwenye ukingo wa simu."</string>
diff --git a/packages/SystemUI/res-product/values-ta/strings.xml b/packages/SystemUI/res-product/values-ta/strings.xml
index 967afed..774134e 100644
--- a/packages/SystemUI/res-product/values-ta/strings.xml
+++ b/packages/SystemUI/res-product/values-ta/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"மொபைலை அன்லாக் செய்ய, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயன்றுவிட்டதனால் பணிக் கணக்கு அகற்றப்படும். இதனால் அதிலுள்ள அனைத்துச் சுயவிவரத் தரவும் நீக்கப்படும்."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"அன்லாக் பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி டேப்லெட்டை அன்லாக் செய்யும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"அன்லாக் பேட்டர்னை, <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துவிட்டீர்கள். இன்னும் <xliff:g id="NUMBER_1">%2$d</xliff:g> முறை தவறாக வரைந்தால், மின்னஞ்சல் கணக்கைப் பயன்படுத்தி மொபைலை அன்லாக் செய்யும்படி கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகளில் மீண்டும் முயலவும்."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"மொபைல் சூடானதால் அணைக்கப்பட்டது"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"சாதனம் சூடானதால் அணைக்கப்பட்டது"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"டேப்லெட் சூடானதால் அணைக்கப்பட்டது"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"இப்போது உங்கள் மொபைல் இயல்புநிலையில் இயங்குகிறது.\nமேலும் தகவலுக்குத் தட்டவும்."</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"இப்போது உங்கள் சாதனம் இயல்புநிலையில் இயங்குகிறது.\nமேலும் தகவலுக்குத் தட்டவும்."</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"இப்போது உங்கள் டேப்லெட் இயல்புநிலையில் இயங்குகிறது.\nமேலும் தகவலுக்குத் தட்டவும்."</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"உங்கள் மொபைல் அதிக சூடானதால் அதன் சூட்டைக் குறைக்க அணைக்கப்பட்டது. இப்போது உங்கள் மொபைல் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருபவற்றைச் செய்தால், உங்கள் மொபைல் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (கேமிங், வீடியோ, வழிகாட்டுதல் ஆப்ஸ் போன்றவை) பயன்படுத்துதல்\n • பெரிய ஃபைல்களைப் பதிவிறக்குதல்/பதிவேற்றுதல்\n • அதிக வெப்பநிலையில் மொபைலைப் பயன்படுத்துதல்"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"உங்கள் சாதனம் அதிக சூடானதால் அதன் சூட்டைக் குறைக்க அணைக்கப்பட்டது. இப்போது உங்கள் சாதனம் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருபவற்றைச் செய்தால், உங்கள் சாதனம் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (கேமிங், வீடியோ, வழிகாட்டுதல் ஆப்ஸ் போன்றவை) பயன்படுத்துதல்\n • பெரிய ஃபைல்களைப் பதிவிறக்குதல்/பதிவேற்றுதல்\n • அதிக வெப்பநிலையில் சாதனத்தைப் பயன்படுத்துதல்"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"உங்கள் டேப்லெட் அதிக சூடானதால் அதன் சூட்டைக் குறைக்க அணைக்கப்பட்டது. இப்போது உங்கள் டேப்லெட் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருபவற்றைச் செய்தால், உங்கள் டேப்லெட் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (கேமிங், வீடியோ, வழிகாட்டுதல் ஆப்ஸ் போன்றவை) பயன்படுத்துதல்\n • பெரிய ஃபைல்களைப் பதிவிறக்குதல்/பதிவேற்றுதல்\n • அதிக வெப்பநிலையில் டேப்லெட்டைப் பயன்படுத்துதல்"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"மொபைல் சூடாகிறது"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"சாதனம் சூடாகிறது"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"டேப்லெட் சூடாகிறது"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"மொபைலின் சூடு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்குத் தட்டவும்."</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"சாதனத்தின் சூடு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்குத் தட்டவும்."</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"டேப்லெட்டின் சூடு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்குத் தட்டவும்."</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"உங்கள் மொபைல் தானாகவே அதன் சூட்டைக் குறைக்க முயலும். தொடர்ந்து மொபைலை உங்களால் பயன்படுத்த முடியும். ஆனால் அது மெதுவாக இயங்கக்கூடும்.\n\nஉங்கள் மொபைலின் சூடு குறைந்தவுடன் அது இயல்பாக இயங்கும்."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"உங்கள் சாதனம் தானாகவே அதன் சூட்டைக் குறைக்க முயலும். தொடர்ந்து சாதனத்தை உங்களால் பயன்படுத்த முடியும். ஆனால் அது மெதுவாக இயங்கக்கூடும்.\n\nஉங்கள் சாதனத்தின் சூடு குறைந்தவுடன் அது இயல்பாக இயங்கும்."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"உங்கள் டேப்லெட் தானாகவே அதன் சூட்டைக் குறைக்க முயலும். தொடர்ந்து டேப்லெட்டை உங்களால் பயன்படுத்த முடியும். ஆனால் அது மெதுவாக இயங்கக்கூடும்.\n\nஉங்கள் டேப்லெட்டின் சூடு குறைந்தவுடன் அது இயல்பாக இயங்கும்."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"\'கைரேகை சென்சார்\' பவர் பட்டனில் உள்ளது. இது டேப்லெட்டின் விளிம்பில் சற்று மேலெழும்பிய ஒலியளவு பட்டனுக்கு அடுத்துள்ள தட்டையான பட்டனாகும்."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"\'கைரேகை சென்சார்\' பவர் பட்டனில் உள்ளது. இது சாதனத்தின் விளிம்பில் சற்று மேலெழும்பிய ஒலியளவு பட்டனுக்கு அடுத்துள்ள தட்டையான பட்டனாகும்."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"\'கைரேகை சென்சார்\' பவர் பட்டனில் உள்ளது. இது மொபைலின் விளிம்பில் சற்று மேலெழும்பிய ஒலியளவு பட்டனுக்கு அடுத்துள்ள தட்டையான பட்டனாகும்."</string>
diff --git a/packages/SystemUI/res-product/values-te/strings.xml b/packages/SystemUI/res-product/values-te/strings.xml
index 80622f5..357b274 100644
--- a/packages/SystemUI/res-product/values-te/strings.xml
+++ b/packages/SystemUI/res-product/values-te/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పు ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, దీని వలన ప్రొఫైల్ డేటా మొత్తం తొలగించబడుతుంది."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఈమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ట్రై చేయండి."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> ప్రయత్నాలలో విఫలమైతే, మీరు ఈమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సి వస్తుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ట్రై చేయండి."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"వేడెక్కినందుకు ఫోన్ ఆఫ్ చేయబడింది"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"వేడెక్కినందుకు పరికరం ఆఫ్ చేయబడింది"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"వేడెక్కినందుకు టాబ్లెట్ ఆఫ్ చేయబడింది"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తోంది.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"మీ పరికరం ఇప్పుడు సాధారణంగా పని చేస్తోంది.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"మీ టాబ్లెట్ ఇప్పుడు సాధారణంగా పని చేస్తోంది.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n • రిసోర్స్-ఆధారిత యాప్లు (వీడియో గేమ్లు, వీడియో లేదా నావిగేషన్ వంటి యాప్లు) ఉపయోగించడం\n • పెద్ద ఫైల్స్ను డౌన్లోడ్ లేదా అప్లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ ఫోన్ని ఉపయోగించడం"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"మీ పరికరం చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ పరికరం ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ పరికరం చాలా వేడెక్కవచ్చు:\n • రిసోర్స్-ఆధారిత యాప్లు (వీడియో గేమ్లు, వీడియో లేదా నావిగేషన్ వంటి యాప్లు) ఉపయోగించడం\n • పెద్ద ఫైల్స్ను డౌన్లోడ్ లేదా అప్లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ పరికరాన్ని ఉపయోగించడం"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"మీ టాబ్లెట్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ టాబ్లెట్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ టాబ్లెట్ చాలా వేడెక్కవచ్చు:\n • రిసోర్స్-ఆధారిత యాప్లు (వీడియో గేమ్లు, వీడియో లేదా నావిగేషన్ వంటి యాప్లు) ఉపయోగించడం\n • పెద్ద ఫైల్స్ను డౌన్లోడ్ లేదా అప్లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ టాబ్లెట్ను ఉపయోగించడం"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"ఫోన్ వేడెక్కుతోంది"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"పరికరం వేడెక్కుతోంది"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"టాబ్లెట్ వేడెక్కుతోంది"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ఫోన్ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"పరికరాన్ని చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"టాబ్లెట్ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"మీ ఫోన్ ఆటోమేటిక్గా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"మీ పరికరం ఆటోమేటిక్గా చల్లబరచడానికి ట్రై చేస్తుంది. మీరు ఇప్పటికీ మీ పరికరాన్ని ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ పరికరం చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"మీ టాబ్లెట్ ఆటోమేటిక్గా చల్లబరచడానికి ట్రై చేస్తుంది. మీరు ఇప్పటికీ మీ టాబ్లెట్ని ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ టాబ్లెట్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"వేలిముద్ర సెన్సార్ పవర్ బటన్పై ఉంది. ఇది, ఈ టాబ్లెట్ అంచున ఉబ్బెత్తుగా ఉన్న వాల్యూమ్ బటన్ పక్కన ఉన్న ఫ్లాట్ బటన్."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"వేలిముద్ర సెన్సార్ పవర్ బటన్పై ఉంది. ఇది, ఈ పరికరం అంచున ఉబ్బెత్తుగా ఉన్న వాల్యూమ్ బటన్ పక్కన ఉన్న ఫ్లాట్ బటన్."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"వేలిముద్ర సెన్సార్ పవర్ బటన్పై ఉంది. ఇది, ఈ ఫోన్ అంచున ఉబ్బెత్తుగా ఉన్న వాల్యూమ్ బటన్ పక్కన ఉన్న ఫ్లాట్ బటన్."</string>
diff --git a/packages/SystemUI/res-product/values-th/strings.xml b/packages/SystemUI/res-product/values-th/strings.xml
index e3d5640..ae1f3ed 100644
--- a/packages/SystemUI/res-product/values-th/strings.xml
+++ b/packages/SystemUI/res-product/values-th/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้งแล้ว ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลทั้งหมดในโปรไฟล์"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"โทรศัพท์ปิดไปเพราะร้อนมาก"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"อุปกรณ์ปิดไปเพราะร้อนมาก"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"แท็บเล็ตปิดไปเพราะร้อนมาก"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"ขณะนี้โทรศัพท์ทำงานเป็นปกติ\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"ขณะนี้อุปกรณ์ทำงานเป็นปกติ\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"ขณะนี้แท็บเล็ตทำงานเป็นปกติ\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"โทรศัพท์ร้อนเกินไปจึงปิดเครื่องเพื่อให้เย็นลง ขณะนี้โทรศัพท์ทำงานเป็นปกติ\n\nโทรศัพท์อาจร้อนเกินไปหากคุณ\n • ใช้แอปที่ใช้ทรัพยากรมาก (เช่น เกม วิดีโอ หรือแอปการนำทาง)\n • ดาวน์โหลดหรืออัปโหลดไฟล์ขนาดใหญ่\n • ใช้โทรศัพท์ในอุณหภูมิที่สูง"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"อุปกรณ์ร้อนเกินไปจึงปิดเครื่องเพื่อให้เย็นลง ขณะนี้อุปกรณ์ทำงานเป็นปกติ\n\nอุปกรณ์อาจร้อนเกินไปหากคุณ\n • ใช้แอปที่ใช้ทรัพยากรมาก (เช่น เกม วิดีโอ หรือแอปการนำทาง)\n • ดาวน์โหลดหรืออัปโหลดไฟล์ขนาดใหญ่\n • ใช้อุปกรณ์ในอุณหภูมิที่สูง"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"แท็บเล็ตร้อนเกินไปจึงปิดเครื่องเพื่อให้เย็นลง ขณะนี้แท็บเล็ตทำงานเป็นปกติ\n\nแท็บเล็ตอาจร้อนเกินไปหากคุณ\n • ใช้แอปที่ใช้ทรัพยากรมาก (เช่น เกม วิดีโอ หรือแอปการนำทาง)\n • ดาวน์โหลดหรืออัปโหลดไฟล์ขนาดใหญ่\n • ใช้แท็บเล็ตในอุณหภูมิที่สูง"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"โทรศัพท์เริ่มร้อน"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"อุปกรณ์เริ่มร้อน"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"แท็บเล็ตเริ่มร้อน"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์เย็นลง\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะอุปกรณ์เย็นลง\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะแท็บเล็ตเย็นลง\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"โทรศัพท์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้โทรศัพท์ได้ แต่อาจทำงานช้าลง\n\nโทรศัพท์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"อุปกรณ์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้อุปกรณ์ได้ แต่อาจทำงานช้าลง\n\nอุปกรณ์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"แท็บเล็ตจะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้แท็บเล็ตได้ แต่อาจทำงานช้าลง\n\nแท็บเล็ตจะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"เซ็นเซอร์ลายนิ้วมืออยู่ที่ปุ่มเปิด/ปิด ซึ่งเป็นปุ่มแบนข้างปุ่มนูนที่ใช้ปรับระดับเสียงตรงบริเวณขอบของแท็บเล็ต"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"เซ็นเซอร์ลายนิ้วมืออยู่ที่ปุ่มเปิด/ปิด ซึ่งเป็นปุ่มแบนข้างปุ่มนูนที่ใช้ปรับระดับเสียงตรงบริเวณขอบของอุปกรณ์"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"เซ็นเซอร์ลายนิ้วมืออยู่ที่ปุ่มเปิด/ปิด ซึ่งเป็นปุ่มแบนข้างปุ่มนูนที่ใช้ปรับระดับเสียงตรงบริเวณขอบของโทรศัพท์"</string>
diff --git a/packages/SystemUI/res-product/values-tl/strings.xml b/packages/SystemUI/res-product/values-tl/strings.xml
index 4c286eb..74f30ae 100644
--- a/packages/SystemUI/res-product/values-tl/strings.xml
+++ b/packages/SystemUI/res-product/values-tl/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Aalisin ang profile sa trabaho, na magiging dahilan para ma-delete ang lahat ng data sa profile."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses kang nagkamali sa pagguhit ng iyong pattern sa pag-unlock. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account.\n\n Subukan ulit sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses kang nagkamali sa pagguhit ng iyong pattern sa pag-unlock. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukan ulit sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Na-off ang telepono dahil sa init"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Na-off ang device dahil sa init"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Na-off ang tablet dahil sa init"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Maayos na ngayong gumagana ang iyong telepono.\nMag-tap para sa higit pang impormasyon"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Maayos na ngayong gumagana ang iyong device.\nMag-tap para sa higit pang impormasyon"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Maayos na ngayong gumagana ang iyong tablet.\nMag-tap para sa higit pang impormasyon"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Napakainit ng telepono mo, kaya nag-off ito para magpalamig. Maayos na itong gumagana.\n\nPosibleng lubos na uminit ang iyong telepono kapag:\n • Gumagamit ka ng mga resource-intensive na app (gaya ng app para sa gaming, video, o pag-navigate)\n • Nagda-download o nag-a-upload ka ng malalaking file\n • Ginagamit mo ang iyong telepono sa maiinit na lugar"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Napakainit ng device mo, kaya nag-off ito para magpalamig. Maayos na itong gumagana.\n\nPosibleng lubos na uminit ang iyong device kapag:\n • Gumagamit ka ng mga resource-intensive na app (gaya ng app para sa gaming, video, o pag-navigate)\n • Nagda-download o nag-a-upload ka ng malalaking file\n • Ginagamit mo ang iyong device sa maiinit na lugar"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Napakainit ng tablet mo, kaya nag-off ito para magpalamig. Maayos na itong gumagana.\n\nPosibleng lubos na uminit ang iyong tablet kapag:\n • Gumagamit ka ng mga resource-intensive na app (gaya ng app para sa gaming, video, o pag-navigate)\n • Nagda-download o nag-a-upload ka ng malalaking file\n • Ginagamit mo ang iyong tablet sa maiinit na lugar"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Umiinit ang telepono"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Umiinit ang device"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Umiinit ang tablet"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Limitado ang ilang feature habang nagpapalamig ang telepono.\nMag-tap para sa higit pang impormasyon"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Limitado ang ilang feature habang nagpapalamig ang device.\nMag-tap para sa higit pang impormasyon"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Limitado ang ilang feature habang nagpapalamig ang tablet.\nMag-tap para sa higit pang impormasyon"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Awtomatikong susubukan ng iyong telepono na magpalamig. Magagamit mo pa rin ang iyong telepono, pero posibleng mas mabagal ang paggana nito.\n\nKapag lumamig na ang telepono mo, gagana ito gaya ng karaniwan."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Awtomatikong susubukan ng iyong device na magpalamig. Magagamit mo pa rin ang iyong device, pero posibleng mas mabagal ang paggana nito.\n\nKapag lumamig na ang device mo, gagana ito gaya ng karaniwan."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Awtomatikong susubukan ng iyong tablet na magpalamig. Magagamit mo pa rin ang iyong tablet, pero posibleng mas mabagal ang paggana nito.\n\nKapag lumamig na ang tablet mo, gagana ito gaya ng karaniwan."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Nasa power button ang sensor para sa fingerprint. Ito ang flat na button sa tabi ng nakaangat na button ng volume sa gilid ng tablet."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Nasa power button ang sensor para sa fingerprint. Ito ang flat na button sa tabi ng nakaangat na button ng volume sa gilid ng device."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Nasa power button ang sensor para sa fingerprint. Ito ang flat na button sa tabi ng nakaangat na button ng volume sa gilid ng telepono."</string>
diff --git a/packages/SystemUI/res-product/values-tr/strings.xml b/packages/SystemUI/res-product/values-tr/strings.xml
index b376e98..68183e4 100644
--- a/packages/SystemUI/res-product/values-tr/strings.xml
+++ b/packages/SystemUI/res-product/values-tr/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. İş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez hatalı çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız tabletinizin kilidini bir e-posta hesabı kullanarak açmanız istenir.\n<xliff:g id="NUMBER_2">%3$d</xliff:g>\n saniye içinde tekrar deneyin."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız deneme daha yaparsanız telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon ısındığından kapatıldı"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Cihaz ısındığından kapatıldı"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Tablet ısındığından kapatıldı"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Telefonunuz şu anda normal bir şekilde çalışıyor.\nDaha fazla bilgi için dokunun"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Cihazınız şu anda normal bir şekilde çalışıyor.\nDaha fazla bilgi için dokunun"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Tabletiniz şu anda normal bir şekilde çalışıyor.\nDaha fazla bilgi için dokunun"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefonunuz çok ısındığından soğuması için kapatıldı ve şu anda normal bir şekilde çalışıyor.\n\nTelefonunuz şu koşullarda çok ısınabilir:\n • Yoğun kaynak gerektiren uygulamalar (oyun, video veya gezinme uygulamaları gibi) kullanma\n • Büyük dosyalar indirme veya yükleme\n • Telefonunuzu sıcak yerlerde kullanma"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Cihazınız çok ısındığından soğuması için kapatıldı ve şu anda normal bir şekilde çalışıyor.\n\nAygıtınız şu koşullarda çok ısınabilir:\n • Yoğun kaynak gerektiren uygulamalar (oyun, video veya gezinme uygulamaları gibi) kullanma\n • Büyük dosyalar indirme veya yükleme\n • Cihazınızı sıcak yerlerde kullanma"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Tabletiniz çok ısındığından soğuması için kapatıldı ve şu anda normal bir şekilde çalışıyor.\n\nTabletiniz şu koşullarda çok ısınabilir:\n • Yoğun kaynak gerektiren uygulamalar (oyun, video veya gezinme uygulamaları gibi) kullanma\n • Büyük dosyalar indirme veya yükleme\n • Tabletinizi sıcak yerlerde kullanma"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon ısınıyor"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Cihaz ısınıyor"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Tablet ısınıyor"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir.\nDaha fazla bilgi için dokunun"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir.\nDaha fazla bilgi için dokunun"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Tablet soğurken bazı özellikler sınırlı olarak kullanılabilir.\nDaha fazla bilgi için dokunun"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefonunuz otomatik olarak soğumaya çalışacak. Bu sırada telefonunuzu kullanmaya devam edebilirsiniz ancak uygulamalar daha yavaş çalışabilir.\n\nTelefonunuz soğuduktan sonra normal şekilde çalışacaktır."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Cihazınız otomatik olarak soğumaya çalışacak. Cihazınız bu sırada kullanılabilir ancak daha yavaş çalışabilir.\n\nCihazınız soğuduktan sonra normal şekilde çalışacaktır."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Tabletiniz otomatik olarak soğumaya çalışacak. Tabletiniz bu sırada kullanılabilir ancak daha yavaş çalışabilir.\n\nTabletiniz soğuduktan sonra normal şekilde çalışacaktır."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Parmak izi sensörü güç düğmesinin üzerindedir. Bu sensör, tabletin kenarındaki standart ses düğmesinin yanında bulunan düz düğmedir."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Parmak izi sensörü güç düğmesinin üzerindedir. Bu sensör, cihazın kenarındaki standart ses düğmesinin yanında bulunan düz düğmedir."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Parmak izi sensörü güç düğmesinin üzerindedir. Bu sensör, telefonun kenarındaki standart ses düğmesinin yanında bulunan düz düğmedir."</string>
diff --git a/packages/SystemUI/res-product/values-uk/strings.xml b/packages/SystemUI/res-product/values-uk/strings.xml
index ed0762b..e0aff9e8 100644
--- a/packages/SystemUI/res-product/values-uk/strings.xml
+++ b/packages/SystemUI/res-product/values-uk/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з\'явиться запит розблокувати планшет за допомогою облікового запису електронної пошти.\n\n Повторіть спробу за <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з\'явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу за <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Телефон перегрівся й вимкнувся"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Пристрій перегрівся й вимкнувся"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Планшет перегрівся й вимкнувся"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Зараз телефон працює як зазвичай.\nНатисніть, щоб дізнатися більше"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Зараз пристрій працює як зазвичай.\nНатисніть, щоб дізнатися більше"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Зараз планшет працює як зазвичай.\nНатисніть, щоб дізнатися більше"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Телефон перегрівся, тому вимкнувся, щоб охолонути. Зараз він працює як зазвичай.\n\nТелефон може перегріватися, якщо ви:\n • використовуєте ресурсомісткі додатки (наприклад, ігри, додатки з відео чи для навігації);\n • завантажуєте великі файли на телефон або з нього;\n • використовуєте телефон за високої температури."</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Пристрій перегрівся, тому вимкнувся, щоб охолонути. Зараз він працює як зазвичай.\n\nПристрій може перегріватися, якщо ви:\n • використовуєте ресурсомісткі додатки (наприклад, ігри, додатки з відео чи для навігації);\n • завантажуєте великі файли на пристрій або з нього;\n • використовуєте пристрій за високої температури."</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Планшет перегрівся, тому вимкнувся, щоб охолонути. Зараз він працює як зазвичай.\n\nПланшет може перегріватися, якщо ви:\n • використовуєте ресурсомісткі додатки (наприклад, ігри, додатки з відео чи для навігації);\n • завантажуєте великі файли на планшет або з нього;\n • використовуєте планшет за високої температури."</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Телефон нагрівається"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Пристрій нагрівається"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Планшет нагрівається"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Під час охолодження телефона деякі функції обмежуються.\nНатисніть, щоб дізнатися більше"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Під час охолодження пристрою деякі функції обмежуються.\nНатисніть, щоб дізнатися більше"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Під час охолодження планшета деякі функції обмежуються.\nНатисніть, щоб дізнатися більше"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Ваш телефон автоматично спробує охолодитися. Ви можете й далі користуватися ним, але він може працювати повільніше.\n\nКоли телефон охолоне, він знову працюватиме як зазвичай."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Ваш пристрій автоматично спробує охолодитися. Ви можете й далі користуватися ним, але він може працювати повільніше.\n\nКоли пристрій охолоне, він знову працюватиме як зазвичай."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Ваш планшет автоматично спробує охолодитися. Ви можете й далі користуватися ним, але він може працювати повільніше.\n\nКоли планшет охолоне, він знову працюватиме як зазвичай."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Сканер відбитків пальців розташовано на кнопці живлення. Це плоска кнопка поруч із випуклою кнопкою гучності на бічній крайці планшета."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Сканер відбитків пальців розташовано на кнопці живлення. Це плоска кнопка поруч із випуклою кнопкою гучності на бічній крайці пристрою."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Сканер відбитків пальців розташовано на кнопці живлення. Це плоска кнопка поруч із випуклою кнопкою гучності на бічній крайці телефона."</string>
diff --git a/packages/SystemUI/res-product/values-ur/strings.xml b/packages/SystemUI/res-product/values-ur/strings.xml
index c706aba..98fe163 100644
--- a/packages/SystemUI/res-product/values-ur/strings.xml
+++ b/packages/SystemUI/res-product/values-ur/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دی جائے گی، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کر کے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کر کے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"گرم ہونے کی وجہ سے فون آف ہو گیا"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"گرم ہونے کی وجہ سے آلہ آف ہو گیا"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"گرم ہونے کی وجہ سے ٹیبلیٹ آف ہو گیا"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"آپ کا فون اب حسب معمول چل رہا ہے۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"آپ کا آلہ اب حسب معمول چل رہا ہے۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"آپ کا ٹیبلیٹ اب حسب معمول چل رہا ہے۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"آپ کا فون کافی گرم ہو گيا تھا، اس لئے ٹھنڈا ہونے کیلئے یہ آف ہو گیا۔ اب آپ کا فون حسب معمول کام کر رہا ہے۔\n\nمندرجہ ذیل چیزیں کرنے پر آپ کا فون کافی گرم ہو سکتا ہے:\n • ماخذ کا زیادہ استعمال کرنے والی ایپس (جیسے کہ گیمنگ، ویڈیو، یا نیویگیشن ایپس) کا استعمال کرنا\n • بڑی فائلز ڈاؤن لوڈ یا اپ لوڈ کرنا\n • اعلی درجہ حرارت میں فون کا استعمال کرنا"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"آپ کا آلہ کافی گرم ہو گيا تھا، اس لئے ٹھنڈا ہونے کیلئے یہ آف ہو گیا۔ اب آپ کا آلہ حسب معمول کام کر رہا ہے۔\n\nمندرجہ ذیل چیزیں کرنے پر آپ کا آلہ کافی گرم ہو سکتا ہے:\n • ماخذ کا زیادہ استعمال کرنے والی ایپس (جیسے کہ گیمنگ، ویڈیو، یا نیویگیشن ایپس) کا استعمال کرنا\n • بڑی فائلز ڈاؤن لوڈ یا اپ لوڈ کرنا\n • اعلی درجہ حرارت میں آلہ کا استعمال کرنا"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"آپ کا ٹیبلیٹ کافی گرم ہو گيا تھا، اس لئے ٹھنڈا ہونے کیلئے یہ آف ہو گیا۔ اب آپ کا ٹیبلیٹ حسب معمول کام کر رہا ہے۔\n\nمندرجہ ذیل چیزیں کرنے پر آپ کا ٹیبلیٹ کافی گرم ہو سکتا ہے:\n • ماخذ کا زیادہ استعمال کرنے والی ایپس (جیسے کہ گیمنگ، ویڈیو، یا نیویگیشن ایپس) کا استعمال کرنا\n • بڑی فائلز ڈاؤن لوڈ یا اپ لوڈ کرنا\n • اعلی درجہ حرارت میں اپنے ٹیبلیٹ کا استعمال کرنا"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"فون گرم ہو رہا ہے"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"آلہ گرم ہو رہا ہے"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"ٹیبلیٹ گرم ہو رہا ہے"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"فون کے ٹھنڈا ہونے تک کچھ خصوصیات محدود ہیں۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"آلہ کے ٹھنڈا ہونے تک کچھ خصوصیات محدود ہیں۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"ٹیبلیٹ کے ٹھنڈا ہونے تک کچھ خصوصیات محدود ہیں۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"آپ کا فون خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ ابھی بھی اپنا فون استعمال کر سکتے ہیں، مگر ہو سکتا ہے یہ سست چلے۔\n\nآپ کا فون ٹھنڈا ہونے کے بعد، یہ حسب معمول چلے گا۔"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"آپ کا آلہ خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ اب بھی اپنا آلہ استعمال کر سکتے ہیں، لیکن یہ آہستہ چل سکتا ہے۔\n\nآپ کا آلہ ٹھنڈا ہونے کے بعد، یہ حسب معمول چلے گا۔"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"آپ کا ٹیبلیٹ خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ اب بھی اپنا ٹیبلیٹ استعمال کر سکتے ہیں، لیکن یہ آہستہ چل سکتا ہے۔\n\nآپ کا ٹیبلیٹ ٹھنڈا ہونے کے بعد، یہ حسب معمول چلے گا۔"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"فنگر پرنٹ سینسر پاور بٹن پر موجود ہے۔ یہ ٹیبلیٹ کے کنارے پر ابھرے ہوئے والیوم بٹن کے آگے والا ہموار بٹن ہے۔"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"فنگر پرنٹ سینسر پاور بٹن پر موجود ہے۔ یہ آلے کے کنارے پر ابھرے ہوئے والیوم بٹن کے آگے والا ہموار بٹن ہے۔"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"فنگر پرنٹ سینسر پاور بٹن پر موجود ہے۔ یہ فون کے کنارے پر ابھرے ہوئے والیوم بٹن کے آگے والا ہموار بٹن ہے۔"</string>
diff --git a/packages/SystemUI/res-product/values-uz/strings.xml b/packages/SystemUI/res-product/values-uz/strings.xml
index 3afa159..38f9ebb 100644
--- a/packages/SystemUI/res-product/values-uz/strings.xml
+++ b/packages/SystemUI/res-product/values-uz/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta xato urinish qildingiz. Endi ish profili oʻchirib tashlanadi va undagi barcha maʼlumotlar ham oʻchib ketadi."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailingizdan foydalanib, planshet qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin yana urinib koʻring."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Grafik kalit <xliff:g id="NUMBER_0">%1$d</xliff:g> marta xato chizildi. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan keyin sizdan emailngizdan foydalanib, telefon qulfini ochishingiz soʻraladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan keyin qayta urinib koʻring."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Telefon isib ketgani sababli oʻchirildi"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Qurilma isib ketgani sababli oʻchirildi"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Planshet isib ketgani sababli oʻchirildi"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Endi telefoningiz normal holatda ishlayapti.\nBatafsil axborot uchun bosing"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Endi qurilmangiz normal holatda ishlayapti.\nBatafsil axborot uchun bosing"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Endi planshetingiz normal holatda ishlayapti.\nBatafsil axborot uchun bosing"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Telefon qizib ketganligi sababli sovitish uchun oʻchirilgan edi. Endi telefoningiz normal holatda ishlayapti.\n\nTelefon quyidagi hollarda qizib ketishi mumkin:\n • Resurstalab ilovalar ishlatilganda (masalan, oʻyin, video yoki navigatsiya ilovalari)\n • Katta faylni yuklab olishda yoki yuklashda\n • Telefondan yuqori haroratda foydalanganda"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Qurilma qizib ketganligi sababli sovitish uchun oʻchirilgan edi. Endi qurilmangiz normal holatda ishlayapti.\n\nQurilma quyidagi hollarda qizib ketishi mumkin:\n • Resurstalab ilovalar ishlatilganda (masalan, oʻyin, video yoki navigatsiya ilovalari)\n • Katta faylni yuklab olishda yoki yuklashda\n • Qurilmadan yuqori haroratda foydalanganda"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Planshet qizib ketganligi sababli sovitish uchun oʻchirilgan edi. Endi planshetingiz normal holatda ishlayapti.\n\nPlanshet quyidagi hollarda qizib ketishi mumkin:\n • Resurstalab ilovalar ishlatilganda (masalan, oʻyin, video yoki navigatsiya ilovalari)\n • Katta faylni yuklab olishda yoki yuklashda\n • Planshetdan yuqori haroratda foydalanganda"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Telefon qizimoqda"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Qurilma qizimoqda"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Planshet qizimoqda"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Telefon sovib olishi uchun ayrim funksiyalar cheklanadi.\nBatafsil axborot uchun bosing"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Qurilma sovib olishi uchun ayrim funksiyalar cheklanadi.\nBatafsil axborot uchun bosing"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Planshet sovib olishi uchun ayrim funksiyalar cheklanadi.\nBatafsil axborot uchun bosing"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Telefoningiz avtomatik ravishda oʻzini sovitadi. Telefondan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nTelefon sovishi bilan normal holatda ishlashni boshlaydi."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Qurilmangiz avtomatik ravishda oʻzini sovitadi. Qurilmadan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nQurilma sovishi bilan normal holatda ishlashni boshlaydi."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Planshetingiz avtomatik ravishda oʻzini sovitadi. Planshetdan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nPlanshet sovishi bilan normal holatda ishlashni boshlaydi."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Barmoq izi sensori quvvat tugmasida joylashgan. U tekis tugma planshetning yon chekkasida tovush balandligi tugmasining yonida joylashgan."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Barmoq izi sensori quvvat tugmasida joylashgan. U tekis tugma qurilmaning yon chekkasida tovush balandligi tugmasining yonida joylashgan."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Barmoq izi sensori quvvat tugmasida joylashgan. U tekis tugma telefonning yon chekkasida tovush balandligi tugmasining yonida joylashgan."</string>
diff --git a/packages/SystemUI/res-product/values-vi/strings.xml b/packages/SystemUI/res-product/values-vi/strings.xml
index 6e121c6..fb3f862 100644
--- a/packages/SystemUI/res-product/values-vi/strings.xml
+++ b/packages/SystemUI/res-product/values-vi/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. Hồ sơ công việc sẽ bị xóa, tức là tất cả dữ liệu hồ sơ sẽ bị xóa."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Bạn đã vẽ không chính xác hình mở khóa <xliff:g id="NUMBER_0">%1$d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Hãy thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Điện thoại đã tắt do quá nóng"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Thiết bị đã tắt do quá nóng"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Máy tính bảng đã tắt do quá nóng"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Hiện điện thoại của bạn đang chạy bình thường.\nHãy nhấn để biết thêm thông tin"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Hiện thiết bị của bạn đang chạy bình thường.\nHãy nhấn để biết thêm thông tin"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Hiện máy tính bảng của bạn đang chạy bình thường.\nHãy nhấn để biết thêm thông tin"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Do quá nóng nên điện thoại đã tắt để hạ nhiệt. Hiện điện thoại của bạn đang chạy bình thường.\n\nĐiện thoại có thể bị quá nóng nếu bạn:\n • Dùng các ứng dụng tốn nhiều tài nguyên (như ứng dụng trò chơi, video hoặc chỉ đường)\n • Tải xuống hoặc tải lên tệp có dung lượng lớn\n • Dùng điện thoại ở nhiệt độ cao"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Do quá nóng nên thiết bị đã tắt để hạ nhiệt. Hiện thiết bị của bạn đang chạy bình thường.\n\nThiết bị có thể bị quá nóng nếu bạn:\n • Dùng các ứng dụng tốn nhiều tài nguyên (như ứng dụng trò chơi, video hoặc chỉ đường)\n • Tải xuống hoặc tải lên tệp có dung lượng lớn\n • Dùng thiết bị ở nhiệt độ cao"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Do quá nóng nên máy tính bảng đã tắt để hạ nhiệt. Hiện máy tính bảng của bạn đang chạy bình thường.\n\nMáy tính bảng có thể bị quá nóng nếu bạn:\n • Dùng các ứng dụng tốn nhiều tài nguyên (như ứng dụng trò chơi, video hoặc chỉ đường)\n • Tải xuống hoặc tải lên tệp có dung lượng lớn\n • Dùng máy tính bảng ở nhiệt độ cao"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Điện thoại đang nóng lên"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Thiết bị đang nóng lên"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Máy tính bảng đang nóng lên"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần.\nHãy nhấn để biết thêm thông tin"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Một số tính năng bị hạn chế trong khi thiết bị nguội dần.\nHãy nhấn để biết thêm thông tin"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Một số tính năng bị hạn chế trong khi máy tính bảng nguội dần.\nHãy nhấn để biết thêm thông tin"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Điện thoại của bạn sẽ tự động nguội dần. Bạn vẫn sẽ sử dụng được điện thoại, nhưng điện thoại có thể chạy chậm hơn.\n\nSau khi đã nguội, điện thoại sẽ chạy bình thường."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Thiết bị của bạn sẽ tự động nguội dần. Bạn vẫn sẽ sử dụng được thiết bị, nhưng thiết bị có thể chạy chậm hơn.\n\nSau khi đã nguội, thiết bị sẽ chạy bình thường."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Máy tính bảng của bạn sẽ tự động nguội dần. Bạn vẫn sẽ sử dụng được máy tính bảng, nhưng máy tính bảng có thể chạy chậm hơn.\n\nSau khi đã nguội, máy tính bảng sẽ chạy bình thường."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Cảm biến vân tay nằm trên nút nguồn. Đó là nút phẳng cạnh nút âm lượng nhô lên trên cạnh của máy tính bảng."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Cảm biến vân tay nằm trên nút nguồn. Đó là nút phẳng cạnh nút âm lượng nhô lên trên cạnh của thiết bị."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Cảm biến vân tay nằm trên nút nguồn. Đó là nút phẳng cạnh nút âm lượng nhô lên trên cạnh của điện thoại."</string>
diff --git a/packages/SystemUI/res-product/values-zh-rCN/strings.xml b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
index a60982f..6895219 100644
--- a/packages/SystemUI/res-product/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rCN/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"您尝试解锁手机后失败的次数已达 <xliff:g id="NUMBER">%d</xliff:g> 次。系统将移除此工作资料,而这将删除所有的工作资料数据。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"您已 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"手机先前因过热而关机"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"设备先前因过热而关机"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"平板电脑先前因过热而关机"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"现在,您的手机已恢复正常运行。\n点按即可了解详情"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"现在,您的设备已恢复正常运行。\n点按即可了解详情"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"现在,您的平板电脑已恢复正常运行。\n点按即可了解详情"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"您的手机先前因过热而关机降温。现已恢复正常运行。\n\n以下情况可能会导致您的手机过热:\n • 使用占用大量资源的应用(例如游戏、视频或导航应用)\n • 下载或上传大型文件\n • 在高温环境下使用手机"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"您的设备先前因过热而关机降温。现已恢复正常运行。\n\n以下情况可能会导致您的设备过热:\n • 使用占用大量资源的应用(例如游戏、视频或导航应用)\n • 下载或上传大型文件\n • 在高温环境下使用设备"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"您的平板电脑先前因过热而关机降温。现已恢复正常运行。\n\n以下情况可能会导致您的平板电脑过热:\n • 使用占用大量资源的应用(例如游戏、视频或导航应用)\n • 下载或上传大型文件\n • 在高温环境下使用平板电脑"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"手机温度上升中"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"设备温度上升中"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"平板电脑温度上升中"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"手机降温期间,部分功能的使用会受限制。\n点按即可了解详情"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"设备降温期间,部分功能的使用会受限制。\n点按即可了解详情"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"平板电脑降温期间,部分功能的使用会受限制。\n点按即可了解详情"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"您的手机将自动尝试降温。您依然可以使用您的手机,但是它的运行速度可能会较慢。\n\n手机降温完毕后,就会恢复正常的运行速度。"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"您的设备将自动尝试降温。您依然可以使用您的设备,但是它的运行速度可能会较慢。\n\n设备降温完毕后,就会恢复正常的运行速度。"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"您的平板电脑将自动尝试降温。您依然可以使用您的平板电脑,但是它的运行速度可能会较慢。\n\n平板电脑降温完毕后,就会恢复正常的运行速度。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指纹传感器在电源按钮上。电源按钮是一个扁平按钮,位于平板电脑边缘凸起的音量按钮旁边。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指纹传感器在电源按钮上。电源按钮是一个扁平按钮,位于设备边缘凸起的音量按钮旁边。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指纹传感器在电源按钮上。电源按钮是一个扁平按钮,位于手机边缘凸起的音量按钮旁边。"</string>
diff --git a/packages/SystemUI/res-product/values-zh-rHK/strings.xml b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
index 85f482a..6bcb048 100644
--- a/packages/SystemUI/res-product/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rHK/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統將移除此工作設定檔,而所有設定檔資料亦會一併刪除。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"你已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求你透過電郵帳戶解鎖平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"你已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次。如果之後再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求你透過電郵帳戶解鎖手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"手機因過熱而關機"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"裝置因過熱而關機"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"平板電腦因過熱而關機"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"你的手機現已正常運作。\n輕按即可瞭解詳情"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"你的裝置現已正常運作。\n輕按即可瞭解詳情"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"你的平板電腦現已正常運作。\n輕按即可瞭解詳情"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"你的手機之前因過熱而關機降溫。手機現已正常運作。\n\n以下情況可能會導致手機過熱:\n • 使用耗用大量資源的應用程式 (例如遊戲、影片或導航應用程式)\n • 下載或上載大型檔案\n • 在高溫環境下使用手機"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"你的裝置之前因過熱而關機降溫。裝置現已正常運作。\n\n以下情況可能會導致裝置過熱:\n • 使用耗用大量資源的應用程式 (例如遊戲、影片或導航應用程式)\n • 下載或上載大型檔案\n • 在高溫環境下使用裝置"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"你的平板電腦之前因過熱而關機降溫。平板電腦現已正常運作。\n\n以下情況可能會導致平板電腦過熱:\n • 使用耗用大量資源的應用程式 (例如遊戲、影片或導航應用程式)\n • 下載或上載大型檔案\n • 在高溫環境下使用平板電腦"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"手機溫度正在上升"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"裝置溫度正在上升"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"平板電腦溫度正在上升"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"手機降溫時,部分功能會受限制。\n輕按即可瞭解詳情"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"裝置降溫時,部分功能會受限制。\n輕按即可瞭解詳情"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"平板電腦降溫時,部分功能會受限制。\n輕按即可瞭解詳情"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"手機會自動嘗試降溫。你仍可以使用手機,但手機的運作速度可能較慢。\n\n手機降溫後便會正常運作。"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"裝置會自動嘗試降溫。你仍可以使用裝置,但裝置的運作速度可能較慢。\n\n裝置降溫後便會正常運作。"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"平板電腦會自動嘗試降溫。你仍可以使用平板電腦,但平板電腦的運作速度可能較慢。\n\n平板電腦降溫後便會正常運作。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指紋感應器位於開關按鈕上,開關按鈕形狀扁平,位於平板電腦邊緣凸起的音量按鈕旁。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指紋感應器位於開關按鈕上,開關按鈕形狀扁平,位於裝置邊緣凸起的音量按鈕旁。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指紋感應器位於開關按鈕上,開關按鈕形狀扁平,位於手機邊緣凸起的音量按鈕旁。"</string>
diff --git a/packages/SystemUI/res-product/values-zh-rTW/strings.xml b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
index c0f75c7..8b79732f 100644
--- a/packages/SystemUI/res-product/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-product/values-zh-rTW/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"你嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。你的工作資料夾將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會要求你透過電子郵件帳戶將平板電腦解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,系統會要求你透過電子郵件帳戶將手機解鎖。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"手機因過熱而關機"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"裝置因過熱而關機"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"平板電腦因過熱而關機"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"手機現在已恢復正常運作。\n輕觸即可瞭解詳情"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"裝置現在已恢復正常運作。\n輕觸即可瞭解詳情"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"平板電腦現在已恢復正常運作。\n輕觸即可瞭解詳情"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"手機先前過熱,因此關機降溫,現在已恢復正常運作。\n\n以下狀況可能會導致手機過熱:\n • 使用的應用程式需要大量資源,例如遊戲、影片或導航應用程式\n • 下載或上傳大型檔案\n • 在高溫下使用手機"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"裝置先前過熱,因此關機降溫,現在已恢復正常運作。\n\n以下狀況可能會導致裝置過熱:\n • 使用的應用程式需要大量資源,例如遊戲、影片或導航應用程式\n • 下載或上傳大型檔案\n • 在高溫下使用裝置"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"平板電腦先前過熱,因此關機降溫,現在已恢復正常運作。\n\n以下狀況可能會導致平板電腦過熱:\n • 使用的應用程式需要大量資源,例如遊戲、影片或導航應用程式\n • 下載或上傳大型檔案\n • 在高溫下使用平板電腦"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"手機溫度上升"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"裝置溫度上升"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"平板電腦溫度上升"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"手機降溫時,某些功能會受到限制。\n輕觸即可瞭解詳情"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"裝置降溫時,某些功能會受到限制。\n輕觸即可瞭解詳情"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"平板電腦降溫時,某些功能會受到限制。\n輕觸即可瞭解詳情"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"手機會自動嘗試降溫。你仍可繼續使用手機,但運作速度可能會變慢。\n\n手機降溫後就會恢復正常運作。"</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"裝置會自動嘗試降溫。你仍可繼續使用裝置,但運作速度可能會變慢。\n\n裝置降溫後就會恢復正常運作。"</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"平板電腦會自動嘗試降溫。你仍可繼續使用平板電腦,但運作速度可能會變慢。\n\n平板電腦降溫後就會恢復正常運作。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"指紋感應器在電源鍵上。電源鍵的形狀是扁平的,位在平板電腦側邊凸起的音量按鈕旁。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"指紋感應器在電源鍵上。電源鍵的形狀是扁平的,位在裝置側邊凸起的音量按鈕旁。"</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"指紋感應器在電源鍵上。電源鍵的形狀是扁平的,位在手機側邊凸起的音量鍵旁。"</string>
diff --git a/packages/SystemUI/res-product/values-zu/strings.xml b/packages/SystemUI/res-product/values-zu/strings.xml
index 6b20014..89d4264 100644
--- a/packages/SystemUI/res-product/values-zu/strings.xml
+++ b/packages/SystemUI/res-product/values-zu/strings.xml
@@ -40,6 +40,24 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Udwebe ngokungalungile iphethini yakho yokuvula ngezikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Ngemuva kwemizamo engaphumelelanga kaningi engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuthi uvule ithebulethi yakho usebenzisa i-akhawunti ye-imeyili.\n\nZama futhi kumasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> imizuzwana."</string>
+ <string name="thermal_shutdown_title" product="default" msgid="8039593017174903505">"Ifoni ivaliwe ngenxa yokushisa"</string>
+ <string name="thermal_shutdown_title" product="device" msgid="2954206342842856379">"Idivayisi ivaliwe ngenxa yokushisa"</string>
+ <string name="thermal_shutdown_title" product="tablet" msgid="8941033526856177533">"Ithebulethi ivaliwe ngenxa yokushisa"</string>
+ <string name="thermal_shutdown_message" product="default" msgid="6685194547904051408">"Ifoni yakho manje isebenza ngokuvamile.\nThepha ukuze uthole ulwazi olungeziwe"</string>
+ <string name="thermal_shutdown_message" product="device" msgid="3039675532521590478">"Idivayisi yakho manje isebenza ngokuvamile.\nThepha ukuze uthole ulwazi olwengeziwe"</string>
+ <string name="thermal_shutdown_message" product="tablet" msgid="5285898074484811386">"Ithebulethi yakho manje isebenza ngokuvamile.\nThepha ukuze uthole ulwazi olwengeziwe"</string>
+ <string name="thermal_shutdown_dialog_message" product="default" msgid="6145923570358574186">"Ifoni yakho ibishisa kakhulu, ngakho-ke yacisha ukuze iphole. Ifoni yakho manje isebenza ngokuvamile.\n\nIfoni yakho ingashisa kakhulu uma:\n • Usebenzisa izinhlelo zokusebenza ezinkulu (njegegeyimu, ividiyo, noma ama-app okufuna)\n • Landa noma layisha amafayela amakhulu\n • Sebenzisa ifoni yakho kumazinga okushisa aphezulu"</string>
+ <string name="thermal_shutdown_dialog_message" product="device" msgid="3647879000909527365">"Idivayisi yakho ibishisa kakhulu, ngakho-ke yacisha ukuze iphole. Idivayisi yakho manje isebenza ngokuvamile.\n\nIdivayisi yakho ingashisa kakhulu uma:\n • Usebenzisa ama-app wensiza enamandla (njegegeyimu, ividiyo, noma ama-app wokufuna)\n • Dawuniloda noma layisha amafayela amakhulu\n • Sebenzisa idivayisi yakho kumazinga wokushisa aphezulu"</string>
+ <string name="thermal_shutdown_dialog_message" product="tablet" msgid="8274487811928782165">"Ithebulethi yakho ibishisa kakhulu, ngakho-ke yacisha ukuze iphole. Ithebulethi yakho manje isebenza ngokuvamile.\n\nIthebulethi yakho ingashisa kakhulu uma:\n • Usebenzisa ama-app wensiza enamandla (njegegeyimu, ividiyo, noma ama-app wokufuna)\n • Dawuniloda noma layisha amafayela amakhulu\n • Sebenzisa ithebulethi yakho kumazinga wokushisa aphezulu kakhulu"</string>
+ <string name="high_temp_title" product="default" msgid="5365000411304924115">"Ifoni iyafudumala"</string>
+ <string name="high_temp_title" product="device" msgid="6622009907401563664">"Idivayisi iyafudumala"</string>
+ <string name="high_temp_title" product="tablet" msgid="9039733706606446616">"Ithebulethi iyafudumala"</string>
+ <string name="high_temp_notif_message" product="default" msgid="3928947950087257452">"Ezinye izakhi zikhawulelwe ngenkathi ifoni iphola.\nThepha mayelana nolwazi olwengeziwe"</string>
+ <string name="high_temp_notif_message" product="device" msgid="6105125771372547292">"Ezinye izakhi zikhawulelwe ngenkathi idivayisi iphola.\nThepha mayelana nolwazi olwengeziwe"</string>
+ <string name="high_temp_notif_message" product="tablet" msgid="7799279192797476850">"Ezinye izakhi zikhawulelwe ngenkathi ithebulethi iphola.\nThepha mayelana nolwazi olwengeziwe"</string>
+ <string name="high_temp_dialog_message" product="default" msgid="4272882413847595625">"Ifoni yakho izozama ngokuzenzakalela ukuphola. Ungasasebenzisa ifoni yakho, kodwa ingasebenza ngokungasheshi.\n\nUma ifoni yakho isipholile, izosebenza ngokuvamile."</string>
+ <string name="high_temp_dialog_message" product="device" msgid="263861943935989046">"Idivayisi yakho izozama ukupholisa ngokuzenzekelayo. Usengasebenzisa idivayisi yakho, kodwa ingase isebenze ngokunensayo.\n\nLapho idivayisi yakho isipholile, izosebenza ngokuvamile."</string>
+ <string name="high_temp_dialog_message" product="tablet" msgid="5613713326841935537">"Ithebulethi yakho izozama ukupholisa. Usengasebenzisa ithebulethi yakho, kodwa ingase isebenze ngokunensayo.\n\nLapho ithebulethi yakho isipholile, izosebenza ngokuvamile."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="tablet" msgid="3726972508570143945">"Inzwa yesigxivizo somunwe esenkinobhweni yamandla. Inkinobho eyisicaba eduze kwenkinobho yevolumu ephakanyisiwe emaphethelweni wethebulethi."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="device" msgid="2929467060295094725">"Inzwa yesigxivizo somunwe esenkinobhweni yamandla. Inkinobho eyisicaba eduze kwenkinobho yevolumu ephakanyisiwe emaphethelweni edivayisi."</string>
<string name="security_settings_sfps_enroll_find_sensor_message" product="default" msgid="8582726566542997639">"Inzwa yesigxivizo somunwe esenkinobhweni yamandla. Inkinobho eyisicaba eduze kwenkinobho yevolumu ephakanyisiwe emaphethelweni efoni."</string>
diff --git a/core/res/res/color/letterbox_background.xml b/packages/SystemUI/res/color/brightness_slider_overlay_color.xml
similarity index 69%
copy from core/res/res/color/letterbox_background.xml
copy to packages/SystemUI/res/color/brightness_slider_overlay_color.xml
index 955948a..a8abd79 100644
--- a/core/res/res/color/letterbox_background.xml
+++ b/packages/SystemUI/res/color/brightness_slider_overlay_color.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,6 +14,9 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
+
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@color/system_neutral1_500" android:lStar="5" />
-</selector>
+ <item android:state_pressed="true" android:color="?attr/onShadeActive" android:alpha="0.12" />
+ <item android:state_hovered="true" android:color="?attr/onShadeActive" android:alpha="0.09" />
+ <item android:color="@color/transparent" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
index 2ea90c7..a9e7adf 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
@@ -26,6 +26,13 @@
<corners android:radius="@dimen/rounded_slider_corner_radius"/>
</shape>
</item>
+ <item>
+ <shape>
+ <corners android:radius="@dimen/rounded_slider_corner_radius" />
+ <size android:height="@dimen/rounded_slider_height" />
+ <solid android:color="@color/brightness_slider_overlay_color" />
+ </shape>
+ </item>
<item
android:id="@+id/slider_icon"
android:gravity="center_vertical|right"
diff --git a/packages/SystemUI/res/drawable/ic_expand_more_48dp.xml b/packages/SystemUI/res/drawable/ic_expand_more_48dp.xml
new file mode 100644
index 0000000..c61a300
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_expand_more_48dp.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48.0dp"
+ android:height="48.0dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M33.17,17.17L24.0,26.34l-9.17,-9.17L12.0,20.0l12.0,12.0 12.0,-12.0z"/>
+</vector>
diff --git a/core/res/res/color/letterbox_background.xml b/packages/SystemUI/res/drawable/immersive_cling_bg_circ.xml
similarity index 64%
copy from core/res/res/color/letterbox_background.xml
copy to packages/SystemUI/res/drawable/immersive_cling_bg_circ.xml
index 955948a..4029702 100644
--- a/core/res/res/color/letterbox_background.xml
+++ b/packages/SystemUI/res/drawable/immersive_cling_bg_circ.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,8 +12,15 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License.
+ ~ limitations under the License
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@color/system_neutral1_500" android:lStar="5" />
-</selector>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval" >
+
+ <solid android:color="@android:color/white" />
+
+ <size
+ android:height="56dp"
+ android:width="56dp" />
+
+</shape>
diff --git a/core/res/res/color/letterbox_background.xml b/packages/SystemUI/res/drawable/immersive_cling_light_bg_circ.xml
similarity index 65%
copy from core/res/res/color/letterbox_background.xml
copy to packages/SystemUI/res/drawable/immersive_cling_light_bg_circ.xml
index 955948a..e3c7d0c 100644
--- a/core/res/res/color/letterbox_background.xml
+++ b/packages/SystemUI/res/drawable/immersive_cling_light_bg_circ.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2022 The Android Open Source Project
+ ~ Copyright (C) 2023 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,8 +12,15 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License.
+ ~ limitations under the License
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@color/system_neutral1_500" android:lStar="5" />
-</selector>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval" >
+
+ <solid android:color="#80ffffff" />
+
+ <size
+ android:height="76dp"
+ android:width="76dp" />
+
+</shape>
diff --git a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
index 87b5a4c..32dc4b3 100644
--- a/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
+++ b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml
@@ -20,7 +20,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface"/>
+ <solid android:color="?androidprv:attr/materialColorSurfaceContainerHigh"/>
<size
android:width="@dimen/keyguard_affordance_fixed_width"
android:height="@dimen/keyguard_affordance_fixed_height"/>
diff --git a/packages/SystemUI/res/layout/biometric_prompt_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
index 05ff1b1..8eb62ec 100644
--- a/packages/SystemUI/res/layout/biometric_prompt_layout.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
@@ -39,6 +39,7 @@
android:singleLine="true"
android:marqueeRepeatLimit="1"
android:ellipsize="marquee"
+ android:importantForAccessibility="no"
style="@style/TextAppearance.AuthCredential.Subtitle"/>
<TextView
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index 665c612..f3a6bbe 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -121,10 +121,12 @@
<LinearLayout
android:id="@+id/shade_header_system_icons"
android:layout_width="wrap_content"
- app:layout_constraintHeight_min="@dimen/large_screen_shade_header_min_height"
- android:layout_height="@dimen/large_screen_shade_header_min_height"
+ android:layout_height="@dimen/shade_header_system_icons_height"
android:clickable="true"
android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingStart="@dimen/shade_header_system_icons_padding_start"
+ android:paddingEnd="@dimen/shade_header_system_icons_padding_end"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@id/privacy_container"
app:layout_constraintTop_toTopOf="@id/clock">
@@ -132,13 +134,13 @@
<com.android.systemui.statusbar.phone.StatusIconContainer
android:id="@+id/statusIcons"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:paddingEnd="@dimen/signal_cluster_battery_padding" />
<com.android.systemui.battery.BatteryMeterView
android:id="@+id/batteryRemainingIcon"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
app:textAppearance="@style/TextAppearance.QS.Status" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/connected_display_chip.xml b/packages/SystemUI/res/layout/connected_display_chip.xml
new file mode 100644
index 0000000..d9df91e
--- /dev/null
+++ b/packages/SystemUI/res/layout/connected_display_chip.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/connected_display_chip"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical|end"
+ tools:parentTag="com.android.systemui.statusbar.ConnectedDisplayChip">
+
+
+ <FrameLayout
+ android:id="@+id/icons_rounded_container"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/ongoing_appops_chip_height"
+ android:layout_gravity="center"
+ android:background="@drawable/statusbar_chip_bg"
+ android:clipToOutline="true"
+ android:clipToPadding="false"
+ android:gravity="center"
+ android:maxWidth="@dimen/ongoing_appops_chip_max_width"
+ android:minWidth="@dimen/ongoing_appops_chip_min_width">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginHorizontal="10dp"
+ android:scaleType="centerInside"
+ android:src="@drawable/stat_sys_connected_display"
+ android:tint="@android:color/black" />
+ </FrameLayout>
+</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
index 50dcaf3..bb32022 100644
--- a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -57,7 +57,6 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
- android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_alarm"
android:tint="@android:color/white"
android:visibility="gone"
@@ -68,7 +67,6 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
- android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_qs_dnd_on"
android:tint="@android:color/white"
android:visibility="gone"
@@ -79,7 +77,6 @@
android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/dream_overlay_status_icon_margin"
- android:layout_marginTop="@dimen/dream_overlay_status_bar_marginTop"
android:src="@drawable/ic_signal_wifi_off"
android:visibility="gone"
android:contentDescription="@string/dream_overlay_status_bar_wifi_off" />
diff --git a/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml b/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml
index bacb5c1..49744e7 100644
--- a/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml
+++ b/packages/SystemUI/res/layout/heads_up_status_bar_layout.xml
@@ -27,8 +27,8 @@
view. -->
<Space
android:id="@+id/icon_placeholder"
- android:layout_width="@dimen/status_bar_icon_drawing_size"
- android:layout_height="@dimen/status_bar_icon_drawing_size"
+ android:layout_width="@dimen/status_bar_icon_size_sp"
+ android:layout_height="@dimen/status_bar_icon_size_sp"
android:layout_gravity="center_vertical"
/>
<TextView
diff --git a/packages/SystemUI/res/layout/immersive_mode_cling.xml b/packages/SystemUI/res/layout/immersive_mode_cling.xml
new file mode 100644
index 0000000..bfb8184
--- /dev/null
+++ b/packages/SystemUI/res/layout/immersive_mode_cling.xml
@@ -0,0 +1,91 @@
+<?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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:paddingBottom="24dp">
+
+ <FrameLayout
+ android:id="@+id/immersive_cling_chevron"
+ android:layout_width="76dp"
+ android:layout_height="76dp"
+ android:layout_marginTop="-24dp"
+ android:layout_centerHorizontal="true">
+
+ <ImageView
+ android:id="@+id/immersive_cling_back_bg_light"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="center"
+ android:src="@drawable/immersive_cling_light_bg_circ" />
+
+ <ImageView
+ android:id="@+id/immersive_cling_back_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="center"
+ android:src="@drawable/immersive_cling_bg_circ" />
+
+ <ImageView
+ android:id="@+id/immersive_cling_ic_expand_more"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="8dp"
+ android:scaleType="center"
+ android:src="@drawable/ic_expand_more_48dp"/>
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/immersive_cling_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/immersive_cling_chevron"
+ android:paddingEnd="48dp"
+ android:paddingStart="48dp"
+ android:paddingTop="40dp"
+ android:text="@string/immersive_cling_title"
+ android:textColor="@android:color/white"
+ android:textSize="24sp" />
+
+ <TextView
+ android:id="@+id/immersive_cling_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/immersive_cling_title"
+ android:paddingEnd="48dp"
+ android:paddingStart="48dp"
+ android:paddingTop="12.6dp"
+ android:text="@string/immersive_cling_description"
+ android:textColor="@android:color/white"
+ android:textSize="16sp" />
+
+ <Button
+ android:id="@+id/ok"
+ style="@android:style/Widget.Material.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_below="@+id/immersive_cling_description"
+ android:layout_marginEnd="40dp"
+ android:layout_marginTop="18dp"
+ android:paddingEnd="8dp"
+ android:paddingStart="8dp"
+ android:text="@string/immersive_cling_positive"
+ android:textColor="@android:color/white"
+ android:textSize="14sp" />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index e95c6a7..91550b3 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -34,5 +34,6 @@
android:paddingEnd="0dp"
android:progressDrawable="@drawable/brightness_progress_drawable"
android:splitTrack="false"
+ android:clickable="true"
/>
</com.android.systemui.settings.brightness.BrightnessSliderView>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 6b8f3cf..909f19f 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -32,7 +32,7 @@
<ImageView
android:id="@+id/notification_lights_out"
- android:layout_width="@dimen/status_bar_icon_size"
+ android:layout_width="@dimen/status_bar_icon_size_sp"
android:layout_height="match_parent"
android:paddingStart="@dimen/status_bar_padding_start"
android:paddingBottom="2dip"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index db94c92..909048e 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -17,10 +17,9 @@
<!-- Extends Framelayout -->
<com.android.systemui.statusbar.notification.row.FooterView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
android:visibility="gone">
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/content"
@@ -37,31 +36,45 @@
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceButton"
android:text="@string/unlock_to_see_notif_text"/>
- <com.android.systemui.statusbar.notification.row.FooterViewButton
- style="@style/TextAppearance.NotificationSectionHeaderButton"
- android:id="@+id/manage_text"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginTop="12dp"
- android:layout_gravity="start"
- android:background="@drawable/notif_footer_btn_background"
- android:focusable="true"
- android:textColor="@color/notif_pill_text"
- android:contentDescription="@string/manage_notifications_history_text"
- android:text="@string/manage_notifications_history_text"
- />
- <com.android.systemui.statusbar.notification.row.FooterViewButton
- style="@style/TextAppearance.NotificationSectionHeaderButton"
- android:id="@+id/dismiss_text"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_marginTop="12dp"
- android:layout_gravity="end"
- android:background="@drawable/notif_footer_btn_background"
- android:focusable="true"
- android:textColor="@color/notif_pill_text"
- android:contentDescription="@string/accessibility_clear_all"
- android:text="@string/clear_all_notifications_text"
- />
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ <com.android.systemui.statusbar.notification.row.FooterViewButton
+ style="@style/TextAppearance.NotificationSectionHeaderButton"
+ android:id="@+id/manage_text"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginTop="12dp"
+ android:layout_marginStart="16dp"
+ app:layout_constraintVertical_bias="0.0"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/dismiss_text"
+ android:background="@drawable/notif_footer_btn_background"
+ android:focusable="true"
+ android:textColor="@color/notif_pill_text"
+ android:contentDescription="@string/manage_notifications_history_text"
+ android:text="@string/manage_notifications_history_text"
+ />
+ <com.android.systemui.statusbar.notification.row.FooterViewButton
+ style="@style/TextAppearance.NotificationSectionHeaderButton"
+ android:id="@+id/dismiss_text"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:layout_marginTop="12dp"
+ android:layout_marginEnd="16dp"
+ app:layout_constraintVertical_bias="1.0"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toEndOf="@id/manage_text"
+ android:background="@drawable/notif_footer_btn_background"
+ android:focusable="true"
+ android:textColor="@color/notif_pill_text"
+ android:contentDescription="@string/accessibility_clear_all"
+ android:text="@string/clear_all_notifications_text"
+ />
+ </androidx.constraintlayout.widget.ConstraintLayout>
</com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
</com.android.systemui.statusbar.notification.row.FooterView>
diff --git a/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
index 0ea0653..4c5cd7d 100644
--- a/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
+++ b/packages/SystemUI/res/layout/status_bar_wifi_group_inner.xml
@@ -24,16 +24,17 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
- android:layout_marginStart="2.5dp"
+ android:layout_marginStart="2.5sp"
>
<FrameLayout
android:id="@+id/inout_container"
- android:layout_height="17dp"
+ android:layout_height="@dimen/status_bar_wifi_inout_container_size"
android:layout_width="wrap_content"
android:gravity="center_vertical" >
<ImageView
android:id="@+id/wifi_in"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/status_bar_wifi_signal_size"
+ android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
@@ -41,7 +42,8 @@
/>
<ImageView
android:id="@+id/wifi_out"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/status_bar_wifi_signal_size"
+ android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
android:paddingEnd="2dp"
@@ -75,7 +77,7 @@
<View
android:id="@+id/wifi_airplane_spacer"
android:layout_width="@dimen/status_bar_airplane_spacer_width"
- android:layout_height="4dp"
+ android:layout_height="wrap_content"
android:visibility="gone"
/>
</com.android.keyguard.AlphaOptimizedLinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 2fa9711..5bd2184 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Aktiveer USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Kom meer te wete"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Verleng Ontsluiting is gedeaktiveer"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Hou Ontsluit is gedeaktiveer"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Stoor tans skermskoot in werkprofiel …"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/af-kieslys"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Sluitskerm"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Foon afgeskakel weens hitte"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Jou foon werk nou normaal.\nTik vir meer inligting"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Jou foon was te warm en dit het afgeskakel om af te koel. Jou foon werk nou normaal.\n\nJou foon kan dalk te warm word as jy:\n • Hulpbron-intensiewe programme (soos dobbel-, video- of navigasieprogramme) gebruik\n • Groot lêers af- of oplaai\n • Jou foon in hoë temperature gebruik"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sien versorgingstappe"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Foon raak warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Sommige kenmerke is beperk terwyl foon afkoel.\nTik vir meer inligting"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Jou foon sal outomaties probeer om af te koel. Jy kan steeds jou foon gebruik, maar dit sal dalk stadiger wees.\n\nJou foon sal normaalweg werk nadat dit afgekoel het."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sien versorgingstappe"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Prop jou toestel uit"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Jou toestel word tans warm naby die laaipoort. Prop dit uit as dit aan ’n laaier of USB-bykomstigheid gekoppel is. Wees versigtig, aangesien die kabel dalk ook warm is."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 6d6b435..f2eb766 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"ዩኤስቢ አንቃ"</string>
<string name="learn_more" msgid="4690632085667273811">"የበለጠ ለመረዳት"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገፅ እይታ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"መክፈትን አራዝም ተሰናክሏል"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock ተሰናክሏል"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገፅ እይታ በማስቀመጥ ላይ..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ቅጽበታዊ ገፅ እይታን ወደ የስራ መገለጫ በማስቀመጥ ላይ…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"የኃይል ምናሌ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ገፅ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ማያ ገፅ ቁልፍ"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ስልክ በሙቀት ምክንያት ጠፍቷል"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"የእርስዎ ስልክ በመደበኛ ሁኔታ እየሠራ ነው።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"የእርስዎ ስልክ በጣም ግሎ ነበር፣ ስለዚህ እንዲቀዘቅዝ ጠፍቷል። የእርስዎ ስልክ አሁን በመደበኝነት እያሄደ ነው።\n\nየሚከተሉትን ካደረጉ የእርስዎ በጣም ሊግል ይችላል፦\n • ኃይል በጣም የሚጠቀሙ መተግበሪያዎችን (እንደ ጨዋታ፣ ቪዲዮ ወይም የአሰሳ መተግበሪያዎች ያሉ) ከተጠቀሙ\n • ትላልቅ ፋይሎችን ካወረዱ ወይም ከሰቀሉ\n • ስልክዎን በከፍተኛ ሙቀት ውስጥ ከተጠቀሙ"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ስልኩ እየሞቀ ነው"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"አንዳንድ ባሕሪያት ስልኩ እየቀዘቀዘ እያለ ውስን ይሆናሉ።\nለተጨማሪ መረጃ መታ ያድርጉ"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"የእርስዎ ስልክ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ስልክዎን መጠቀም ይችላሉ፣ ነገር ግን ሊንቀራፈፍ ይችላል።\n\nአንዴ ስልክዎ ከቀዘቀዘ በኋላ በመደበኝነት ያሄዳል።"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"መሣሪያዎን ይንቀሉ"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"መሣሪያዎ ከኃይል መሙያ ወደቡ አቅራቢያ እየሞቀ ነው። ከኃይል መሙያ ወይም ከዩኤስቢ ተጨማሪ መሣሪያ ጋር ከተገናኘ ይንቀሉት እና ገመዱ የሞቀ ሊሆን ስለሚችል ጥንቃቄ ያድርጉ።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 614b968..9a74144 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"تفعيل USB"</string>
<string name="learn_more" msgid="4690632085667273811">"مزيد من المعلومات"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"لقطة شاشة"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"تم إيقاف ميزة Extend Unlock."</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"تم إيقاف ميزة \"إبقاء الجهاز مفتوحًا\"."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"أرسَل صورة"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"جارٍ حفظ لقطة الشاشة..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"جارٍ حفظ لقطة الشاشة في الملف الشخصي للعمل…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"قائمة زر التشغيل"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"شاشة القفل"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"تم إيقاف الهاتف بسبب الحرارة"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"يعمل هاتفك الآن بشكل طبيعي.\nانقر للحصول على مزيد من المعلومات."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ارتفعت درجة حرارة هاتفك بشدة، لذا تم إيقاف تشغيله لخفض درجة حرارته. يعمل هاتفك الآن بشكل طبيعي.\n\nقد ترتفع بشدة درجة حرارة هاتفك إذا:\n • استخدمت تطبيقات كثيفة الاستخدام لموارد الجهاز (مثل الألعاب أو الفيديو أو تطبيقات التنقل)\n • نزَّلت أو حمَّلت ملفات كبيرة الحجم\n • استخدمت هاتفك وسط أجواء مرتفعة الحرارة"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"الاطّلاع على خطوات العناية"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"تزداد درجة حرارة الهاتف"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"يتم تقييد عمل بعض الميزات إلى أن تنخفض درجة حرارة الهاتف.\nانقر للحصول على مزيد من المعلومات."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"سيحاول الهاتف تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام هاتفك، ولكن قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الهاتف، سيستعيد سرعته المعتادة."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"الاطّلاع على خطوات العناية"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"افصِل جهازك"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"تزداد حرارة الجهاز بالقرب من منفذ الشحن. إذا كان الجهاز متصلاً بشاحن أو ملحق USB، عليك فصله وتوخي الحذر لأن درجة حرارة الكابل قد تكون مرتفعة أيضًا."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 06c9f53d..856989c 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB সক্ষম কৰক"</string>
<string name="learn_more" msgid="4690632085667273811">"অধিক জানক"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্ৰীনশ্বট"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock অক্ষম কৰা আছে"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"এক্সটেণ্ড আনলক অক্ষম কৰা আছে"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীনশ্বট ছেভ কৰি থকা হৈছে…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"কৰ্মস্থানৰ প্ৰ’ফাইলত স্ক্ৰীনশ্বট ছেভ কৰি থকা হৈছে…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাৱাৰ মেনু"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>ৰ পৃষ্ঠা <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্ৰীন"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"আপোনাৰ ফ\'নটো গৰম হোৱাৰ কাৰণে অফ কৰা হৈছিল"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"আপোনাৰ ফ’নটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\nঅধিক তথ্যৰ বাবে টিপক"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"আপোনাৰ ফ\'নটো অত্যধিক গৰম হোৱাৰ বাবে ইয়াক ঠাণ্ডা কৰিবলৈ অফ কৰা হৈছিল। আপোনাৰ ফ\'নটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\n\nআপোনাৰ ফ\'নটো গৰম হ\'ব পাৰে, যদিহে আপুনি:\n • ফ\'নটোৰ হাৰ্ডৱেৰ অত্যধিক মাত্ৰাত ব্যৱহাৰ কৰা এপ্সমূহ চলালে (যেনে, ভিডিঅ\' গেইম, ভিডিঅ\', দিক্-নিৰ্দেশনা এপ্সমূহ)\n • খুউব ডাঙৰ আকাৰৰ ফাইল আপল\'ড বা ডাউনল’ড কৰিলে\n • আপোনাৰ ফ\'নটো উচ্চ তাপমাত্ৰাৰ পৰিৱেশত ব্যৱহাৰ কৰিলে"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ফ\'নটো গৰম হ\'বলৈ ধৰিছে"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ফ’নটো ঠাণ্ডা হৈ থকাৰ সময়ত কিছুমান সুবিধা উপলব্ধ নহয়।\nঅধিক তথ্যৰ বাবে টিপক"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"আপোনাৰ ফ\'নটোৱে নিজে নিজে ঠাণ্ডা হ\'বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি ফ\'নটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nফ\'নটো সম্পূৰ্ণভাৱে ঠাণ্ডা হোৱাৰ পাছত ই আগৰ নিচিনাকৈয়েই চলিব।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"আপোনাৰ ডিভাইচটো আনপ্লাগ কৰক"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"আপোনাৰ ডিভাইচটো চাৰ্জিং প’ৰ্টৰ ওচৰত গৰম হৈছে। যদি এইটো কোনো চার্জাৰ অথবা ইউএছবিৰ সহায়ক সামগ্ৰীৰ সৈতে সংযুক্ত হৈ আছে, ইয়াক আনপ্লাগ কৰক আৰু কে’বলডালো গৰম হ\'ব পাৰে, গতিকে যত্ন লওক।"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index a413e6b..1c14b04e 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB-ni aktiv edin"</string>
<string name="learn_more" msgid="4690632085667273811">"Ətraflı məlumat"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock deaktiv edilib"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Uzaqdan kiliddən çıxarma deaktiv edilib"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"İş profili skrinşotu saxlanılır…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Qidalanma düyməsi menyusu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran kilidi"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"İstiliyə görə telefon söndü"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonunuz indi normal işləyir.\nƏtraflı məlumat üçün toxunun"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon çox isti idi və soyumaq üçün söndü. Hazırda telefon normal işləyir.\n\n Telefon bu hallarda çox isti ola bilər:\n • Çox resurslu tətbiq istifadə etsəniz (oyun, video və ya naviqasiya tətbiqi kimi)\n • Böyük həcmli fayl endirsəniz və ya yükləsəniz\n • Telefonu yüksək temperaturda istifadə etsəniz"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon qızmağa başlayır"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soyuyana kimi bəzi funksiyalar məhdudlaşdırılır.\nƏtraflı məlumat üçün toxunun"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz avtomatik olaraq soyumağa başlayacaq. Telefon istifadəsinə davam edə bilərsiniz, lakin sürəti yavaşlaya bilər.\n\nTelefonunuz soyuduqdan sonra normal işləyəcək."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Cihazınızı ayırın"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Cihazınız şarj portunun yaxınlığında qızmağa başlayır. Şarj cihazına və ya USB aksesuarına qoşulubsa, onu ayırın və diqqətli olun, çünki kabel də qıza bilər."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 3d52d51..c00cd6a 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni dugmeta za uključivanje"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključan ekran"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se isključio zbog toplote"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon sada normalno radi.\nDodirnite za više informacija"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon je bio prevruć, pa se isključio da se ohladi. Sada radi normalno.\n\nTelefon može previše da se ugreje ako:\n • Koristite aplikacije koje zahtevaju puno resursa (npr. video igre, video ili aplikacije za navigaciju)\n • Preuzimate/otpremate velike datoteke\n • Koristite telefon na visokoj temperaturi"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte upozorenja"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon se zagrejao"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će automatski pokušati da se ohladi. I dalje ćete moći da koristite telefon, ali će sporije reagovati.\n\nKada se telefon ohladi, normalno će raditi."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte upozorenja"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Isključite uređaj"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Uređaj se zagreva u blizini porta za punjenje. Ako je povezan sa punjačem ili USB opremom, isključite je i budite pažljivi jer i kabl može da bude vruć."</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 5f2d7b5..95eebad 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Уключыць USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Даведацца больш"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Здымак экрана"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Функцыя падоўжанай разблакіроўкі адключана"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Функцыя працяглай разблакіроўкі адключана"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Захаванне здымка экрана ў працоўны профіль…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопкі сілкавання"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Экран блакіроўкі"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"З-за перагрэву тэл. выключыўся"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ваш тэлефон працуе нармальна.\nНацісніце, каб даведацца больш"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ваш тэлефон пераграваўся, таму ён выключыўся, каб астыць. Зараз тэлефон працуе нармальна.\n\nТэлефон можа перагравацца пры:\n • Выкарыстанні рэсурсаёмістых праграм (напрыклад, гульняў, відэа або праграм навігацыі)\n • Спампоўцы або запампоўцы вялікіх файлаў\n • Выкарыстанні тэлефона пры высокіх тэмпературах"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Глядзець паэтапную дапамогу"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Тэлефон награваецца"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Некаторыя функцыі абмежаваны, пакуль тэлефон не астыне.\nНацісніце, каб даведацца больш"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш тэлефон аўтаматычна паспрабуе астыць. Вы можаце па-ранейшаму карыстацца сваім тэлефонам, але ён можа працаваць больш павольна.\n\nПасля таго як ваш тэлефон астыне, ён будзе працаваць у звычайным рэжыме."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Глядзець паэтапную дапамогу"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Адключыце прыладу"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Ваша прылада моцна награваецца ў месцы, дзе знаходзіцца зарадны порт. Калі яна падключана да зараднай прылады ці USB-прылады, адключыце яе і будзьце асцярожнымі з кабелем, які таксама можа награвацца."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 9201f40..567a22b 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню за включване/изключване"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заключен екран"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Тел. се изкл. поради загряване"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефонът ви вече работи нормално.\nДокоснете за още информация"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефонът ви бе твърде горещ, затова се изключи с цел охлаждане. Вече работи нормално.\n\nТелефонът ви може да стане твърде горещ, ако:\n • използвате приложения, които ползват голям обем ресурси (като например игри, видеосъдържание или приложения за навигация);\n • изтегляте или качвате големи файлове;\n • използвате устройството си при високи температури."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Вижте стъпките, които да предприемете"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Телефонът загрява"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Някои функции са ограничени, докато телефонът се охлажда.\nДокоснете за още информация"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонът ви автоматично ще направи опит за охлаждане. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Вижте стъпките, които да предприемете"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Изключете устройството си"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Устройството ви се загрява до порта за зареждане. Ако е свързано със зарядно устройство или аксесоар за USB, изключете го и внимавайте, тъй като и кабелът може да е топъл."</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index d8cb70d..38308e2 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"পাওয়ার মেনু"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্রিন"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"আপনার ফোন গরম হওয়ার জন্য বন্ধ হয়ে গেছে"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"আপনার ফোন এখন ভালভাবে কাজ করছে।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"আপনার ফোন খুব বেশি গরম হয়েছিল বলে ঠাণ্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ফোন ঠিক-ঠাক ভাবে চলছে না।\n\nআপনার ফোন খুব বেশি গরম হয়ে যাবে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করলে যেটি আপনার ডিভাইসের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করলে\n • বেশি তাপমাত্রায় আপনার ফোন ব্যবহার করলে"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ফোনটি গরম হচ্ছে"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ফোন ঠাণ্ডা না হওয়া পর্যন্ত কিছু ফিচার কাজ করে না।\nআরও তথ্যের জন্য ট্যাপ করুন"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"আপনার ফোনটি নিজে থেকেই ঠাণ্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠাণ্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ডিভাইস রক্ষণাবেক্ষণের ধাপগুলি দেখুন"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"আপনার ডিভাইস আনপ্লাগ করা"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"চার্জিং পোর্টের কাছে আপনার ডিভাইসটি গরম হচ্ছে। এটি চার্জার বা ইউএসবি অ্যাক্সেসরির সাথে কানেক্ট করা থাকলে, আনপ্লাগ করুন এবং সতর্ক থাকুন কারণ কেবেলটিও গরম হতে পারে।"</string>
@@ -988,7 +982,7 @@
<string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"অডিও আউটপুটের জন্য উপলভ্য ডিভাইস।"</string>
<string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"ভলিউম"</string>
<string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g>%%"</string>
- <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পিকার & ডিসপ্লে"</string>
+ <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"স্পিকার ও ডিসপ্লে"</string>
<string name="media_output_group_title_suggested_device" msgid="4157186235837903826">"সাজেস্ট করা ডিভাইস"</string>
<string name="media_output_end_session_dialog_summary" msgid="5954520685989877347">"অন্য ডিভাইসে মিডিয়া সরাতে আপনার শেয়ার করা সেশন বন্ধ করুন"</string>
<string name="media_output_end_session_dialog_stop" msgid="208189434474624412">"বন্ধ করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 89c964d..eaa0d9d 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni napajanja"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključani ekran"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se isključio zbog pregrijavanja"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Vaš telefon sada radi normalno.\nDodirnite za više informacija"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Vaš telefon se pregrijao, pa se isključio da se ohladi. Telefon sada radi normalno.\n\nTelefon se može pregrijati ako:\n • Koristite aplikacije koje troše puno resursa (kao što su aplikacije za igranje, videozapise ili navigaciju)\n • Preuzimate ili otpremate velike fajlove\n • Koristite telefon na visokim temperaturama"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte korake za zaštitu"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon se pregrijava"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon hladi.\nDodirnite za više informacija"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Vaš telefon će se automatski pokušati ohladiti. I dalje možete koristi telefon, ali će možda raditi sporije.\n\nNakon što se ohladi, telefon će normalno raditi."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte korake za zaštitu"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Iskopčajte uređaj"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Uređaj se zagrijava u blizini priključka za punjenje. Ako je povezan s punjačem ili USB dodatkom, iskopčajte ga i vodite računa jer i kabl može biti topao."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index e0e78ae..6416543 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Activa l\'USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Més informació"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock desactivat"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desbloqueig ampliat desactivat"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"S\'està desant la captura al perfil de treball…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú d\'engegada"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueig"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telèfon apagat per la calor"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ara el telèfon funciona correctament.\nToca per obtenir més informació"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"El telèfon s\'havia sobreescalfat i s\'ha apagat per refredar-se. Ara funciona amb normalitat.\n\nEs pot sobreescalfar si:\n • utilitzes aplicacions que consumeixen molts recursos (com ara, videojocs, vídeos o aplicacions de navegació);\n • baixes o penges fitxers grans;\n • l\'utilitzes amb temperatures altes."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Mostra els passos de manteniment"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"El telèfon s\'està escalfant"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Algunes funcions estan limitades mentre el telèfon es refreda.\nToca per obtenir més informació"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"El telèfon provarà de refredar-se automàticament. Podràs continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Mostra els passos de manteniment"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconnecta el dispositiu"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"El dispositiu s\'està escalfant a prop del port de càrrega. Si està connectat a un carregador o a un accessori USB, desconnecta\'l. Ves amb compte perquè el cable també pot haver-se escalfat."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 522300b..56ae4b8 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Aktivovat USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Další informace"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snímek obrazovky"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Prodloužení odemknutí deaktivováno"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Rozšíření odemknutí deaktivováno"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ukládání snímku obrazovky do pracovního profilu…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Nabídka vypínače"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Obrazovka uzamčení"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se vypnul z důvodu zahřátí"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Nyní telefon funguje jako obvykle.\nKlepnutím zobrazíte další informace"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon byl příliš zahřátý, proto se vypnul, aby vychladl. Nyní telefon funguje jako obvykle.\n\nTelefon se může příliš zahřát v těchto případech:\n • používání náročných aplikací (např. her, videí nebo navigace),\n • stahování nebo nahrávání velkých souborů,\n • používání telefonu při vysokých teplotách."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobrazit pokyny, co dělat"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon se zahřívá"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Některé funkce jsou při chladnutí telefonu omezeny.\nKlepnutím zobrazíte další informace"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž telefon vychladne, bude fungovat normálně."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobrazit pokyny, co dělat"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Odpojte zařízení"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Zařízení se zahřívá v oblasti nabíjecího portu. Pokud je připojeno k nabíječce nebo příslušenství USB, odpojte ho (dejte pozor, kabel také může být zahřátý)."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index e9a522f..0ce9932 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Aktivér USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Få flere oplysninger"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Hold oplåst er deaktiveret"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Hold ulåst er deaktiveret"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendte et billede"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Gemmer screenshot..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Gemmer screenshot på din arbejdsprofil…"</string>
@@ -661,12 +661,12 @@
<string name="group_system_access_system_settings" msgid="7961639365383008053">"Åbn systemindstillinger"</string>
<string name="group_system_access_google_assistant" msgid="1186152943161483864">"Åbn Google Assistent"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Lås skærm"</string>
- <string name="group_system_quick_memo" msgid="2914234890158583919">"Hent appen Notes for at skrive et hurtigt notat"</string>
+ <string name="group_system_quick_memo" msgid="2914234890158583919">"Åbn appen Notes for at skrive et hurtigt notat"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Systemmultitasking"</string>
<string name="system_multitasking_rhs" msgid="6593269428880305699">"Start opdelt skærm med aktuel app til højre"</string>
<string name="system_multitasking_lhs" msgid="8839380725557952846">"Start opdelt skærm med aktuel app til venstre"</string>
<string name="system_multitasking_full_screen" msgid="1962084334200006297">"Skift fra opdelt skærm til fuld skærm"</string>
- <string name="system_multitasking_replace" msgid="844285282472557186">"Ved opdelt skærm: Erstat en app med én app ad gangen"</string>
+ <string name="system_multitasking_replace" msgid="844285282472557186">"Ved opdelt skærm: Erstat en app med en anden app"</string>
<string name="keyboard_shortcut_group_input" msgid="6888282716546625610">"Input"</string>
<string name="input_switch_input_language_next" msgid="3394291576873633793">"Skift inputsprog (næste sprog)"</string>
<string name="input_switch_input_language_previous" msgid="8823659252918609216">"Skift inputsprog (forrige sprog)"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu for afbryderknappen"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskærm"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefonen slukkede pga. varme"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Din telefon kører nu normalt.\nTryk for at få flere oplysninger"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Din telefon var blevet for varm, så den slukkede for at køle ned. Din telefon kører nu igen normalt. \n\nDin telefon kan blive for varm, hvis du:\n • Bruger ressourcekrævende apps (f.eks. spil, video eller navigation)\n • Downloader eller uploader store filer\n • Bruger din telefon i varme omgivelser"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se håndteringsvejledning"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefonen er ved at blive varm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Nogle funktioner er begrænsede, mens telefonen køler ned.\nTryk for at få flere oplysninger"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Din telefon forsøger automatisk at køle ned. Du kan stadig bruge telefonen, men den kører muligvis langsommere.\n\nNår din telefon er kølet ned, fungerer den normalt igen."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se håndteringsvejledning"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Træk stikket ud af din enhed"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Din enhed er ved at blive varm i nærheden af opladningsporten. Hvis enheden er tilsluttet en oplader eller USB-enhed, skal du trække stikket ud. Vær opmærksom på, at stikket også kan være varmt."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index dc06ee1..ef76528 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ein-/Aus-Menü"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Sperrbildschirm"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Ausgeschaltet, da zu heiß"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Dein Smartphone funktioniert jetzt wieder normal.\nFür mehr Informationen tippen."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Dein Smartphone war zu heiß und wurde zum Abkühlen ausgeschaltet. Nun funktioniert es wieder normal.\n\nMögliche Ursachen:\n • Verwendung ressourcenintensiver Apps (z. B. Spiele-, Video- oder Navigations-Apps)\n • Download oder Upload großer Dateien \n • Verwendung des Smartphones bei hohen Temperaturen"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Schritte zur Abkühlung des Geräts ansehen"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Smartphone wird warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Einige Funktionen sind während der Abkühlphase des Smartphones eingeschränkt.\nFür mehr Informationen tippen."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Dein Smartphone kühlt sich automatisch ab. Du kannst dein Smartphone weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Smartphone abgekühlt ist, funktioniert es wieder normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Schritte zur Abkühlung des Geräts ansehen"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Gerät vom Stromnetz trennen"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Dein Gerät erwärmt sich am Ladeanschluss. Trenne das Gerät vom Stromnetz, wenn es an ein Ladegerät oder USB-Zubehör angeschlossen ist. Sei vorsichtig, denn das Kabel könnte ebenfalls heiß sein."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 08d5b4b..2c4b332 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Ενεργοποίηση USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Μάθετε περισσότερα"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Στιγμιότυπο οθόνης"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Το εκτεταμένο ξεκλείδωμα είναι απενεργοποιημένο"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Η Επέκταση ξεκλειδώματος είναι απενεργοποιημένη"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Αποθήκευση στιγμιότ. οθόνης στο προφίλ εργασίας…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Μενού λειτουργίας"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Οθόνη κλειδώματος"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Το τηλέφωνο απεν. λόγω ζέστης"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Το τηλέφωνο λειτουργεί πλέον κανονικά.\nΠατήστε για περισσότερες πληροφορίες."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Η θερμοκρασία του τηλεφώνου είναι πολύ υψηλή και απενεργοποιήθηκε για να κρυώσει. Πλέον, λειτουργεί κανονικά.\n\nΗ θερμοκρασία ενδέχεται να ανέβει κατά τη:\n • Χρήση εφαρμογών υψηλής κατανάλωσης πόρων (όπως gaming, βίντεο ή περιήγησης)\n • Λήψη/μεταφόρτωση μεγάλων αρχείων\n • Χρήση σε υψηλές θερμοκρασίες"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Δείτε βήματα αντιμετώπισης."</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Αύξηση θερμοκρασίας τηλεφώνου"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας.\nΠατήστε για περισσότερες πληροφορίες."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Το τηλέφωνό σας θα προσπαθήσει να μειώσει αυτόματα τη θερμοκρασία. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του τηλεφώνου σας, θα λειτουργεί ξανά κανονικά."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Δείτε βήματα αντιμετώπισης."</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Αποσυνδέστε τη συσκευή"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Η συσκευή έχει αρχίσει να ζεσταίνεται κοντά στη θύρα φόρτισης. Αν είναι συνδεδεμένη σε φορτιστή ή αξεσουάρ USB, αποσυνδέστε την και προσέξτε γιατί και το καλώδιο μπορεί να έχει ζεσταθεί."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e4719e4..03d2a51 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 43d58ca..f328508 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features limited while phone cools down.\nTap for more info"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it, and take care as the cable may also be warm."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e4719e4..03d2a51 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e4719e4..03d2a51 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it and take care as the cable may also be warm."</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index b4c5d10..ed958d8 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video, or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features limited while phone cools down.\nTap for more info"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Unplug your device"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Your device is getting warm near the charging port. If it’s connected to a charger or USB accessory, unplug it, and take care as the cable may also be warm."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0678e68..91b6be6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -414,7 +414,7 @@
<string name="media_projection_entry_generic_permission_dialog_continue" msgid="8640381403048097116">"Iniciar"</string>
<string name="screen_capturing_disabled_by_policy_dialog_title" msgid="2113331792064527203">"Bloqueada por tu administrador de TI"</string>
<string name="screen_capturing_disabled_by_policy_dialog_description" msgid="6015975736747696431">"La captura de pantalla está inhabilitada debido a la política del dispositivo"</string>
- <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
+ <string name="clear_all_notifications_text" msgid="348312370303046130">"Cerrar todo"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Administrar"</string>
<string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
<string name="notification_section_header_incoming" msgid="850925217908095197">"Nuevo"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"El teléfono se apagó por calor"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Tu teléfono ahora se ejecuta con normalidad.\nPresiona para obtener más información"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Tu teléfono estaba muy caliente y se apagó para enfriarse. Ya funciona correctamente.\n\nTu teléfono puede calentarse en estos casos:\n • Usas apps que consumen muchos recursos (como juegos, videos o navegación).\n • Subes o descargas archivos grandes.\n • Usas el teléfono en condiciones de temperatura alta."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"El teléfono se está calentando"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Algunas funciones se limitan durante el enfriamiento del teléfono.\nPresiona para obtener más información"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Tu teléfono intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar correctamente."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Desenchufa el dispositivo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"El puerto de carga del dispositivo se está calentando. Si está conectado a un cargador o accesorio USB, desenchúfalo con cuidado, ya que el cable también puede estar caliente."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 0dfd63c..178c8b1 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Habilitar USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Más información"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock inhabilitado"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Prolongar Desbloqueo inhabilitado"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Guardando captura en el perfil de trabajo…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de encendido"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Teléfono apagado por calor"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"El teléfono ya funciona con normalidad.\nToca para ver más información"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"El teléfono se había calentado demasiado y se ha apagado para enfriarse. Ahora funciona con normalidad.\n\nPuede calentarse demasiado si:\n • Usas aplicaciones que consumen muchos recursos (p. ej., apps de juegos, vídeos o navegación)\n • Descargas o subes archivos grandes\n • Lo usas a altas temperaturas"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"El teléfono se está calentando"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Se han limitado algunas funciones mientras el teléfono se enfría.\nToca para ver más información"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"El teléfono intentará enfriarse. Puedes seguir utilizándolo, pero es posible que funcione con mayor lentitud.\n\nUna vez que se haya enfriado, funcionará con normalidad."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Desenchufa tu dispositivo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Tu dispositivo se está calentando cerca del puerto de carga. Si está conectado a un cargador o a un accesorio USB, desenchúfalo con cuidado, ya que el cable también puede estar caliente."</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index ae75d09..b2470f7 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Luba USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Lisateave"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekraanipilt"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock on keelatud"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Avatuna hoidmine on keelatud"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"saatis kujutise"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Kuvatõmmise salvestamine ..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ekraanipildi salvestamine tööprofiilile …"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Toitemenüü"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lukustuskuva"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Tel. lül. kuumuse tõttu välja"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon töötab nüüd tavapäraselt.\nPuudutage lisateabe saamiseks."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon oli liiga kuum, seetõttu lülitus see jahtumiseks välja. Telefon töötab nüüd tavapäraselt.\n\nTelefon võib kuumaks minna:\n • ressursse koormavate rakenduste kasutamisel (nt mängu-, video- või navigatsioonirakendused)\n • suurte failide alla-/üleslaadimisel\n • telefoni kasutamisel kõrgel temperatuuril"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vaadake hooldusjuhiseid"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon soojeneb"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Mõned funktsioonid on piiratud, kuni telefon jahtub.\nPuudutage lisateabe saamiseks."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Teie telefon proovib automaatselt maha jahtuda. Saate telefoni ikka kasutada, kuid see võib olla aeglasem.\n\nKui telefon on jahtunud, töötab see tavapäraselt."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vaadake hooldusjuhiseid"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Eemaldage seade"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Teie seade läheb laadimispordi juurest soojaks. Kui see on ühendatud laadija või USB-tarvikuga, eemaldage see ja olge ettevaatlik, kuna kaabel võib samuti soe olla."</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index ff78952..33fee8d 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Gaitu USB ataka"</string>
<string name="learn_more" msgid="4690632085667273811">"Lortu informazio gehiago"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Pantaila-argazkia"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desgaitu da desblokeatze luzatua"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desgaitu da desblokeatuta mantentzeko eginbidea"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"erabiltzaileak irudi bat bidali du"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Pantaila-argazkia gordetzen…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Pantaila-argazkia laneko profilean gordetzen…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Itzaltzeko menua"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantaila blokeatua"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Beroegi egoteagatik itzali da"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ohi bezala ari da funtzionatzen telefonoa orain.\nInformazio gehiago lortzeko, sakatu hau."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonoa gehiegi berotu da, eta itzali egin da tenperatura jaisteko. Orain, ohiko moduan dabil.\n\nBerotzearen zergati posibleak:\n • Baliabide asko behar dituzten aplikazioak erabiltzea (adib., bideojokoak, bideoak edo nabigazio-aplikazioak).\n • Fitxategi handiak deskargatu edo kargatzea.\n • Telefonoa giro beroetan erabiltzea."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ikusi zaintzeko urratsak"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Berotzen ari da telefonoa"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte.\nInformazio gehiago lortzeko, sakatu hau."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonoa automatikoki saiatuko da hozten. Hoztu bitartean, telefonoa erabiltzen jarrai dezakezu, baina mantsoago funtziona lezake.\n\nTelefonoaren tenperatura jaitsi bezain laster, ohi bezala funtzionatzen jarraituko du."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ikusi zaintzeko urratsak"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Deskonektatu gailua"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Gailua berotzen ari da kargatzeko atakaren inguruan. Kargagailu edo USB bidezko osagarri batera konektatuta badago, deskonekta ezazu kontuz, kablea ere beroa egongo baita agian."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index cc26355..97f6930 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"منوی روشن/خاموش"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"صفحه قفل"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"تلفن به علت گرم شدن خاموش شد"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"اکنون عملکرد تلفنتان به حالت عادی برگشته است.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"تلفنتان خیلی گرم شده بود، بنابراین خاموش شد تا خنک شود. اکنون تلفنتان عملکرد معمولش را دارد.\n\nتلفنتان خیلی گرم میشود، اگر:\n • از برنامههای نیازمند پردازش زیاد (مانند بازی، برنامههای ویدیویی یا پیمایشی) استفاده کنید\n • فایلهای بزرگ بارگیری یا بارگذاری کنید\n • در دماهای بالا از تلفنتان استفاده کنید"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"دیدن اقدامات محافظتی"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"تلفن درحال گرم شدن است"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"وقتی تلفن درحال خنک شدن است، بعضی از ویژگیها محدود میشوند.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"تلفنتان بهطور خودکار سعی میکند خنک شود. همچنان میتوانید از تلفنتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی تلفن خنک شد، عملکرد عادیاش از سرگرفته میشود."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"دیدن اقدامات محافظتی"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"دستگاه را جدا کنید"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"دستگاهتان کنار درگاه شارژ گرم شده است. اگر دستگاهتان به شارژر یا لوازم جانبی USB متصل است، آن را جدا کنید و مراقب باشید چون ممکن است کابل هم گرم باشد."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 2b93430..abf52fe 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Ota USB käyttöön"</string>
<string name="learn_more" msgid="4690632085667273811">"Lue lisää"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Kuvakaappaus"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock poistettu käytöstä"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Lukitsematon tila poistettu käytöstä"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"lähetti kuvan"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Tallennetaan kuvakaappausta..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Kuvakaappausta tallennetaan työprofiiliin…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Virtavalikko"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lukitusnäyttö"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Puhelin sammui kuumuuden takia"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Puhelimesi toimii nyt normaalisti.\nLue lisää napauttamalla"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Puhelimesi oli liian kuuma, joten se sammui. Puhelimesi toimii nyt normaalisti.\n\nPuhelimesi voi kuumentua liikaa, jos\n • käytät paljon resursseja vaativia sovelluksia (esim. pelejä, videoita tai navigointisovelluksia)\n • lataat tai lähetät suuria tiedostoja\n • käytät puhelintasi korkeissa lämpötiloissa."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Katso huoltovaiheet"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Puhelin lämpenee"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana.\nLue lisää napauttamalla"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Puhelimesi yrittää automaattisesti jäähdyttää itsensä. Voit silti käyttää puhelinta, mutta se voi toimia hitaammin.\n\nKun puhelin on jäähtynyt, se toimii normaalisti."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Katso huoltovaiheet"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Irrota laite"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Laite lämpenee latausportin lähellä. Jos laite on yhdistetty laturiin tai USB-lisälaitteeseen, irrota se varoen, sillä johtokin voi olla lämmin."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 2ac7309..4f94d1f 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Activer l\'USB"</string>
<string name="learn_more" msgid="4690632085667273811">"En savoir plus"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock désactivée"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Déverrouillage prolongé désactivé"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Sauv. de la capture dans le profil prof. en cours…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu de l\'interrupteur"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Tél. éteint car il surchauffait"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Votre téléphone fonctionne maintenant de manière normale.\nTouchez pour en savoir plus"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Votre téléphone s\'est éteint, car il surchauffait. Il s\'est refroidi et fonctionne normalement.\n\nIl peut surchauffer si vous :\n • Util. des applis utilisant beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • Téléchargez ou téléversez de gros fichiers\n • Utilisez téléphone dans des températures élevées"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Le téléphone commence à chauffer"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Certaines fonctionnalités sont limitées pendant que le téléphone refroidit.\nTouchez pour en savoir plus"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Débranchez votre appareil"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Votre appareil chauffe près du port de recharge. S\'il est connecté à un chargeur ou à un accessoire USB, débranchez-le en faisant attention : le câble pourrait également être chaud."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 7646a88..0ede09a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Activer le port USB"</string>
<string name="learn_more" msgid="4690632085667273811">"En savoir plus"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Déverrouillage étendu désactivé"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock désactivé"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Enregistrement de capture d\'écran dans profil pro…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu Marche/Arrêt"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Tél. éteint car il surchauffait"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"À présent, votre téléphone fonctionne normalement.\nAppuyer pour en savoir plus"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Votre téléphone s\'est éteint, car il surchauffait. Il s\'est refroidi et fonctionne normalement.\n\nIl peut surchauffer si vous :\n • exécutez applis utilisant beaucoup de ressources (jeux, vidéo, navigation, etc.) ;\n • téléchargez ou importez gros fichiers ;\n • utilisez téléphone à des températures élevées."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Le téléphone chauffe"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Fonctionnalités limitées pendant le refroidissement du téléphone.\nAppuyer pour en savoir plus"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Débrancher votre appareil"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Votre appareil se réchauffe près du port de recharge. S\'il est connecté à un chargeur ou un accessoire USB, débranchez-le en faisant attention, car le câble peut lui aussi être chaud."</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index cb2375f..1446755 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Activar USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Máis información"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desactivouse o desbloqueo ampliado"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desactivouse Desbloqueo extra"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Gardando captura de pantalla no perfil de traballo"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menú de acendido"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"O teléfono apagouse pola calor"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"O teléfono funciona con normalidade.\nToca para obter máis información"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O teléfono estaba moi quente, apagouse para que arrefríe e agora funciona con normalidade.\n\nÉ posible que estea moi quente se:\n • Usas aplicacións que requiren moitos recursos (como aplicacións de navegación, vídeos e xogos)\n • Descargas/cargas ficheiros grandes\n • Usas o teléfono a alta temperatura"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantemento"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"O teléfono está quentando"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"O uso dalgunhas funcións é limitado mentres o teléfono arrefría.\nToca para obter máis información"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"O teléfono tentará arrefriar automaticamente. Podes utilizalo, pero é probable que funcione máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantemento"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconectar o dispositivo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"O dispositivo estase quentando cerca do porto de carga. Se está conectado a un cargador ou a un accesorio USB, desconéctao con coidado, xa que o cable tamén podería estar quente."</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index c3be28c..89390b1 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB ચાલુ કરો"</string>
<string name="learn_more" msgid="4690632085667273811">"વધુ જાણો"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"સ્ક્રીનશૉટ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlockની સુવિધા બંધ કરવામાં આવી"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"એક્સટેન્ડ અનલૉકની સુવિધા બંધ કરવામાં આવી"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ઑફિસની પ્રોફાઇલમાં સ્ક્રીનશૉટ સાચવી રહ્યાં છીએ…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"પાવર મેનૂ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"લૉક સ્ક્રીન"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ફોન વધુ પડતી ગરમીને લીધે બંધ થઇ ગયો છે"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"તમારો ફોન હવે સામાન્યપણે કાર્ય કરી રહ્યો છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"તમારો ફોન અત્યંત ગરમ હતો, તેથી તે ઠંડો થવા ઑટોમૅટિક રીતે બંધ થઈ ગયો છે. તમારો ફોન હવે સામાન્યપણે કાર્ય કરી રહ્યો છે.\n\nતમારો ફોન અત્યંત ગરમ થઈ શકે છે, જો તમે:\n • એવી ઍપ વાપરતા હો જે સંસાધન સઘન રીતે વાપરતી હોય (જેમ કે ગેમિંગ, વીડિયો, અથવા નેવિગેટ કરતી ઍપ)\n • મોટી ફાઇલો અપલોડ અથવા ડાઉનલોડ કરતા હો\n • તમારા ફોનનો ઉપયોગ ઉચ્ચ તાપમાનમાં કરતા હો"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"સારસંભાળના પગલાં જુઓ"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ફોન ગરમ થઈ રહ્યો છે"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ફોન ઠંડો થાય ત્યાં સુધી અમુક સુવિધાઓ મર્યાદિત હોય છે.\nવધુ માહિતી માટે ટૅપ કરો"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"તમારો ફોન ઑટોમૅટિક રીતે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"સારસંભાળના પગલાં જુઓ"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"તમારા ડિવાઇસને અનપ્લગ કરો"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"તમારું ડિવાઇસ ચાર્જિંગ પોર્ટની પાસે ગરમ થઈ રહ્યું છે. જો તે કોઈ ચાર્જર અથવા USB ઍક્સેસરી સાથે કનેક્ટેડ હોય, તો તેને અનપ્લગ કરો અને ધ્યાન રાખો, કારણ કે કેબલ ગરમ પણ હોઈ શકે છે."</string>
diff --git a/packages/SystemUI/res/values-h800dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
index 3a71994..829ef98 100644
--- a/packages/SystemUI/res/values-h800dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -15,9 +15,6 @@
-->
<resources>
- <!-- With the large clock, move up slightly from the center -->
- <dimen name="keyguard_large_clock_top_margin">-112dp</dimen>
-
<!-- Margin above the ambient indication container -->
<dimen name="ambient_indication_container_margin_top">20dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 60fd680..fb017da 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेन्यू"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"पेज <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्क्रीन"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"गर्म होने की वजह से फ़ोन बंद हुआ"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"आपका फ़ोन सामान्य रूप से काम कर रहा है.\nज़्यादा जानकारी के लिए टैप करें"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"फ़ोन बहुत गर्म हो गया था, इसलिए ठंडा होने के लिए बंद हो गया. फ़ोन अब अच्छे से चल रहा है.\n\nफ़ोन तब बहुत गर्म हो सकता है जब आप:\n • ज़्यादा रिसॉर्स का इस्तेमाल करने वाले ऐप्लिकेशन चलाते हैं (जैसे गेमिंग, वीडियो या नेविगेशन ऐप्लिकेशन)\n • बड़ी फ़ाइलें डाउनलोड या अपलोड करते हैं\n • ज़्यादा तापमान में फ़ोन का इस्तेमाल करते हैं"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"डिवाइस के रखरखाव के तरीके देखें"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"फ़ोन गर्म हो रहा है"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"फ़ोन के ठंडा होने तक कुछ सुविधाएं काम नहीं करतीं.\nज़्यादा जानकारी के लिए टैप करें"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"आपका फ़ोन अपने आप ठंडा होने की कोशिश करेगा. आप अब भी अपने फ़ोन का उपयोग कर सकते हैं, लेकिन हो सकता है कि यह धीमी गति से चले.\n\nठंडा हो जाने पर आपका फ़ोन सामान्य रूप से चलेगा."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिवाइस के रखरखाव के तरीके देखें"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"डिवाइस को अनप्लग करें"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"आपका डिवाइस चार्जिंग पोर्ट के पास गर्म हो रहा है. अगर डिवाइस चार्जर या यूएसबी ऐक्सेसरी से कनेक्ट है, तो उसे अनप्लग करें. साथ ही, ध्यान रखें कि केबल भी गर्म हो सकती है."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 02c1be7..b7a7cdd 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Izbornik tipke za uključivanje/isključivanje"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključani zaslon"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se isključio zbog vrućine"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon sad radi normalno.\nDodirnite za više informacija"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon se pregrijao, stoga se isključio kako bi se ohladio Telefon sada radi normalno.\n\nTelefon se može pregrijati ako:\n • upotrebljavate zahtjevne aplikacije (kao što su igre, aplikacije za videozapise ili navigaciju)\n • preuzimate ili prenosite velike datoteke\n • upotrebljavate telefon na visokim temperaturama."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pročitajte upute za održavanje"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon se zagrijava"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke su značajke ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte upute za održavanje"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Iskopčajte uređaj"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Vaš se uređaj zagrijava u blizini priključka za punjenje. Ako je priključen u punjač ili USB uređaj, iskopčajte ga. Pazite jer se i kabel možda zagrijao."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index b5081d0..6a96fcc 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB engedélyezése"</string>
<string name="learn_more" msgid="4690632085667273811">"Részletek"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Képernyőkép"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock letiltva"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Tartós feloldás letiltva"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Képernyőkép mentése a munkaprofilba…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Bekapcsológombhoz tartozó menü"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lezárási képernyő"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"A meleg miatt kikapcsolt"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonja most már megfelelően működik.\nKoppintson, ha további információra van szüksége."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonja túlmelegedett, így kikapcsolt, hogy lehűlhessen. Most már megfelelően működik.\n\nA telefon akkor melegedhet túl, ha Ön:\n • Energiaigényes alkalmazásokat használ (például játékokat, videókat vagy navigációs alkalmazásokat)\n • Nagy fájlokat tölt le vagy fel\n • Melegben használja a telefonját"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Olvassa el a kímélő használat lépéseit"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"A telefon melegszik"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Bizonyos funkciók korlátozottan működnek a telefon lehűlése közben.\nKoppintson, ha további információra van szüksége."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"A telefon automatikusan megpróbál lehűlni. Továbbra is tudja használni a telefont, de elképzelhető, hogy működése lelassul.\n\nAmint a telefon lehűl, újra a szokásos módon működik majd."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Olvassa el a kímélő használat lépéseit"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Húzza ki az eszközt"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Eszköze kezd melegedni a töltőport közelében. Ha töltő vagy USB-s kiegészítő van csatlakoztatva hozzá, húzza ki, és legyen óvatos, mert a kábel is meleg lehet."</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index cfc92a4..d91b3dd2 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Միացնել USB-ն"</string>
<string name="learn_more" msgid="4690632085667273811">"Իմանալ ավելին"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Սքրինշոթ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"«Երկարացնել կողպումը» գործառույթն անջատված է"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"«Հետաձգված ապակողպում» գործառույթն անջատված է"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Սքրինշոթը պահվում է աշխատանքային պրոֆիլում…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Սնուցման կոճակի ընտրացանկ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Կողպէկրան"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Հեռախոսն անջատվել էր տաքանալու պատճառով"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Հեռախոսն այժմ նորմալ է աշխատում։\nՀպեք՝ ավելին իմանալու համար։"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ձեր հեռախոսը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար: Հեռախոսն այժմ նորմալ աշխատում է:\n\nՀեռախոսը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավիգացիայի հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր հեռախոսը բարձր ջերմային պայմաններում"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Հեռախոսը տաքանում է"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են։\nՀպեք՝ ավելին իմանալու համար։"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ: Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով:"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Անջատեք սարքը"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Լիցքավորման միացքի հատվածում սարքը տաքանում է։ Եթե լիցքավորիչի կամ USB լրասարքի է միացված սարքը, անջատեք այն և զգույշ եղեք, քանի որ մալուխը ևս կարող է տաքացած լինել։"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 515f80f..550b048 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu daya"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Layar kunci"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Ponsel dimatikan karena panas"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ponsel kini berfungsi normal.\nKetuk untuk info selengkapnya"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ponsel menjadi terlalu panas, jadi dimatikan untuk mendinginkan. Ponsel kini berfungsi normal.\n\nPonsel dapat menjadi terlalu panas jika Anda:\n • Menggunakan aplikasi yang menggunakan sumber daya secara intensif (seperti aplikasi game, video, atau navigasi)\n • Mendownload atau mengupload file besar\n • Menggunakan ponsel dalam suhu tinggi"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah-langkah perawatan"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Ponsel menjadi hangat"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Beberapa fitur dibatasi saat ponsel mendingin.\nKetuk untuk info selengkapnya"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ponsel akan otomatis mencoba mendingin. Anda tetap dapat menggunakan ponsel, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, ponsel akan berjalan seperti biasa."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah-langkah perawatan"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Cabut perangkat"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Perangkat menjadi panas saat di dekat port pengisi daya. Jika perangkat terhubung ke pengisi daya atau aksesori USB, cabutlah dan berhati-hatilah karena suhu kabel mungkin juga panas."</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index fb73c0b..86455c0 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Virkja USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Frekari upplýsingar"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skjámynd"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Slökkt á Extend Unlock"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Slökkt á Lengri opnun"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendi mynd"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Vistar skjámynd…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Vistar skjámynd á vinnusnið…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aflrofavalmynd"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lásskjár"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Slökkt var á símanum vegna hita"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Síminn virkar nú eins og venjulega.\nÝttu til að fá frekari upplýsingar"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Síminn varð of heitur og því var slökkt á honum til að kæla hann. Síminn virkar núna sem skyldi.\n\nSíminn getur orðið of heitur ef þú:\n • Notar plássfrek forrit (t.d. leikja-, myndbands- eða leiðsagnarforrit\n • Sækir eða hleður upp stórum skrám\n • Notar símann í miklum hita"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sjá varúðarskref"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Síminn er að hitna"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Sumir eiginleikar eru takmarkaðir meðan síminn kælir sig.\nÝttu til að fá frekari upplýsingar"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Síminn reynir sjálfkrafa að kæla sig. Þú getur enn notað símann en hann gæti verið hægvirkari.\n\nEftir að síminn hefur kælt sig niður virkar hann eðlilega."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sjá varúðarskref"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Taktu tækið úr sambandi"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Tækið er að hitna nálægt hleðslutenginu. Ef það er tengt við hleðslutæki eða USB-aukahlut skaltu taka það úr sambandi og hafa í huga að snúran gæti einnig verið heit."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 62d5a46..17ec328 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Attiva USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Scopri di più"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Funzionalità Extend Unlock disattivata"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Sblocco avanzato disattivato"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Salvataggio screenshot nel profilo di lavoro…"</string>
@@ -661,7 +661,7 @@
<string name="group_system_access_system_settings" msgid="7961639365383008053">"Accedi alle impostazioni di sistema"</string>
<string name="group_system_access_google_assistant" msgid="1186152943161483864">"Accedi all\'Assistente Google"</string>
<string name="group_system_lock_screen" msgid="7391191300363416543">"Blocca lo schermo"</string>
- <string name="group_system_quick_memo" msgid="2914234890158583919">"Visualizza l\'app Note per rapidi appunti"</string>
+ <string name="group_system_quick_memo" msgid="2914234890158583919">"Visualizza l\'app Note per appunti rapidi"</string>
<string name="keyboard_shortcut_group_system_multitasking" msgid="1065232949510862593">"Multitasking di sistema"</string>
<string name="system_multitasking_rhs" msgid="6593269428880305699">"Attiva lo schermo diviso con l\'app corrente a destra"</string>
<string name="system_multitasking_lhs" msgid="8839380725557952846">"Attiva lo schermo diviso con l\'app corrente a sinistra"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu del tasto di accensione"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Schermata di blocco"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Il telefono si è spento perché surriscaldato"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ora il telefono funziona normalmente.\nTocca per ulteriori informazioni"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Il telefono era surriscaldato e si è spento per raffreddarsi. Ora funziona normalmente.\n\nIl telefono può surriscaldarsi se:\n • Utilizzi app che consumano molte risorse (ad esempio app di navigazione, giochi o video)\n • Scarichi o carichi grandi file\n • Lo utilizzi in presenza di alte temperature"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Leggi le misure da adottare"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Il telefono si sta scaldando"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Alcune funzionalità limitate durante il raffreddamento del telefono.\nTocca per ulteriori informazioni"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Il telefono cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il telefono funzionerà normalmente."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Leggi le misure da adottare"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Scollega il dispositivo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Il tuo dispositivo si sta scaldando vicino alla porta di ricarica. Se è collegato a un caricabatterie o a un accessorio USB, scollegalo e fai attenzione perché il cavo potrebbe essere caldo."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 7497bd4..5b317cb 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"הפעלת USB"</string>
<string name="learn_more" msgid="4690632085667273811">"מידע נוסף"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"התכונה \'הרחבה של ביטול הנעילה\' מושבתת"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"התכונה Extend Unlock מושבתת"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"המערכת שומרת את צילום המסך..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"צילום המסך נשמר בפרופיל העבודה…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"תפריט הפעלה"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"מסך נעילה"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"הטלפון כבה עקב התחממות"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"הטלפון פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"הטלפון שלך התחמם יותר מדי וכבה כדי להתקרר. הטלפון פועל כרגיל עכשיו.\n\nייתכן שהטלפון יתחמם יותר מדי אם:\n • משתמשים באפליקציות עתירות משאבים (כגון משחקים, אפליקציות וידאו או אפליקציות ניווט)\n • מורידים או מעלים קבצים גדולים\n • משתמשים בטלפון בסביבה עם טמפרטורות גבוהות"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"לצפייה בשלבי הטיפול"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"הטלפון מתחמם"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"קירור הטלפון ייעשה באופן אוטומטי. ניתן עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"לצפייה בשלבי הטיפול"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ניתוק המכשיר"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"המכשיר שלך מתחמם בקרבת יציאת הטעינה. אם המכשיר מחובר למטען או לאביזר בחיבור USB, צריך לנתק אותו בזהירות כיוון שגם הכבל עלול להיות חם."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d74d2f1..56a78e2 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB を有効にする"</string>
<string name="learn_more" msgid="4690632085667273811">"詳細"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"スクリーンショット"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock は無効です"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ロック解除延長は無効です"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"スクリーンショットを仕事用プロファイルに保存中…"</string>
@@ -654,7 +654,7 @@
<string name="group_system_go_back" msgid="8838454003680364227">"戻る: 前の状態に戻る([戻る] ボタン)"</string>
<string name="group_system_access_home_screen" msgid="1857344316928441909">"ホーム画面にアクセス"</string>
<string name="group_system_overview_open_apps" msgid="6897128761003265350">"開いているアプリの概要"</string>
- <string name="group_system_cycle_forward" msgid="9202444850838205990">"最近使ったアプリを切り替え(進)"</string>
+ <string name="group_system_cycle_forward" msgid="9202444850838205990">"最近使ったアプリを切り替え(進む)"</string>
<string name="group_system_cycle_back" msgid="5163464503638229131">"最近使ったアプリを切り替え(戻る)"</string>
<string name="group_system_access_all_apps_search" msgid="488070738028991753">"すべてのアプリの一覧にアクセスして検索(検索 / ランチャー)"</string>
<string name="group_system_hide_reshow_taskbar" msgid="3809304065624351131">"タスクバーを非表示 /(再)表示"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源ボタン メニュー"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ロック画面"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"高熱で電源が OFF になりました"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"お使いのスマートフォンは現在、正常に動作しています。\nタップして詳細を表示"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"スマートフォンが熱すぎたため電源が OFF になりました。現在は正常に動作しています。\n\nスマートフォンは以下の場合に熱くなる場合があります。\n • リソースを集中的に使用する機能やアプリ(ゲームアプリ、動画アプリ、ナビアプリなど)を使用\n • サイズの大きいファイルをダウンロードまたはアップロード\n • 高温の場所で使用"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"取り扱いに関する手順をご覧ください"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"スマートフォンの温度が上昇中"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"スマートフォンのクールダウン中は一部の機能が制限されます。\nタップして詳細を表示"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"スマートフォンは自動的にクールダウンを行います。その間もスマートフォンを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"取り扱いに関する手順をご覧ください"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"デバイスを電源から外します"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"充電ポートの近くにデバイスを置くと、本体が熱くなります。デバイスが充電器や USB アクセサリに接続されている場合は外してください。ケーブルが熱くなっていることもあるので注意してください。"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 8662f98..f19b6b6 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB-ის ჩართვა"</string>
<string name="learn_more" msgid="4690632085667273811">"შეიტყვეთ მეტი"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ეკრანის ანაბეჭდი"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"გაფართოებული განბლოკვა გაითიშა"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ხანგრძლივი განბლოკვა გაითიშა"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"მიმდინარეობს ეკრანის ანაბეჭდის შენახვა სამუშაო პროფილში…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ჩართვის მენიუ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ჩაკეტილი ეკრანი"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ტელეფონი გამოირთო გაცხელების გამო"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"თქვენი ტელეფონი უკვე ნორმალურად მუშაობს.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"თქვენი ტელეფონი გამოირთო გასაგრილებლად, რადგან ის მეტისმეტად გაცხელდა. ახლა ის ჩვეულებრივად მუშაობს.\n\nტელეფონის გაცხელების მიზეზებია:\n • რესურსტევადი აპების გამოყენება (მაგ. სათამაშო, ვიდეო ან ნავიგაციის აპების)\n • დიდი ფაილების ჩამოტვირთვა ან ატვირთვა\n • ტელეფონის გამოყენება მაღალი ტემპერატურისას"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"მისაღები ზომების გაცნობა"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ტელეფონი ცხელდება"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"თქვენი ტელეფონი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"მისაღები ზომების გაცნობა"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"გამოაერᲗეᲗ Თქვენი მოწყობილობა"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"თქვენი მოწყობილობა ხურდება დამტენის პორტთან ახლოს. თუ ის დაკავშირებულია დამტენთან ან USB აქსესუართან, გამორთეთ იგი და იზრუნეთ, რადგან შესაძლოა კაბელიც გახურებული იყოს."</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 4fd3242..c7d30e7 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Қуат мәзірі"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Құлыптаулы экран"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон қызып кеткендіктен өшірілді"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефоныңыз қалыпты жұмыс істеп тұр.\nТолығырақ ақпарат алу үшін түртіңіз."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефоныңыз қатты қызып кеткендіктен өшірілді. Телефоныңыз қазір қалыпты жұмыс істеп тұр.\n\nТелефоныңыз мына жағдайларда ыстық болуы мүмкін:\n • Ресурстар талап ететін қолданбаларды пайдалану (ойын, бейне немесе навигация қолданбалары)\n • Үлкен көлемді файлдарды жүктеу немесе жүктеп салу\n • Телефонды жоғары температурада пайдалану"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Пайдалану нұсқаулығын қараңыз"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Телефон қызуда"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон толық суығанға дейін, кейбір функциялардың жұмысы шектеледі.\nТолығырақ ақпарат үшін түртіңіз."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nТелефон суығаннан кейін, оның жұмысы қалпына келеді."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Пайдалану нұсқаулығын қараңыз"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Құрылғыны ажыратыңыз"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Құрылғының зарядтау ұяшығы тұрған бөлігі қызып келеді. Зарядтағышқа немесе USB құрылғысына жалғанған болса, оны ажыратыңыз. Абайлаңыз, кабель де ыстық болуы мүмкін."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 5132ac0..375b79d 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"បើក USB"</string>
<string name="learn_more" msgid="4690632085667273811">"ស្វែងយល់បន្ថែម"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"រូបថតអេក្រង់"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"បានបិទការដោះសោបន្ថែម"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"បានបិទ Extend Unlock"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បានផ្ញើរូបភាព"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុងរក្សាទុករូបថតអេក្រង់..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"កំពុងរក្សាទុករូបថតអេក្រង់ទៅកម្រងព័ត៌មានការងារ…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ម៉ឺនុយថាមពល"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"អេក្រង់ចាក់សោ"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ទូរសព្ទបានបិទដោយសារវាឡើងកម្តៅ"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"ឥឡូវនេះ ទូរសព្ទរបស់អ្នកកំពុងដំណើរការជាធម្មតា។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ទូរសព្ទរបស់អ្នកក្តៅពេក ដូច្នេះវាបានបិទដើម្បីបន្ថយកម្តៅ។ ឥឡូវនេះ ទូរសព្ទរបស់អ្នកកំពុងដំណើរការធម្មតា។\n\nទូរសព្ទរបស់អ្នកអាចនឹងឡើងកម្តៅខ្លាំងជ្រុល ប្រសិនបើអ្នក៖\n • ប្រើប្រាស់កម្មវិធីដែលប្រើប្រាស់ទិន្នន័យច្រើនក្នុងរយៈពេលខ្លី (ដូចជាហ្គេម វីដេអូ ឬកម្មវិធីរុករក)\n • ទាញយក ឬបង្ហោះឯកសារដែលមានទំហំធំ\n • ប្រើប្រាស់ទូរសព្ទរបស់អ្នកនៅកន្លែងមានសីតុណ្ហភាពខ្ពស់"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"មើលជំហានថែទាំ"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ទូរសព្ទនេះកំពុងកើនកម្តៅ"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"មុខងារមួយចំនួននឹងមិនអាចប្រើបានពេញលេញនោះទេ ខណៈពេលដែលទូរសព្ទកំពុងបញ្ចុះកម្ដៅ។\nសូមចុចដើម្បីទទួលបានព័ត៌មានបន្ថែម"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"ទូរសព្ទរបស់អ្នកនឹងព្យាយាមបញ្ចុះកម្តៅដោយស្វ័យប្រវត្តិ។ អ្នកនៅតែអាចប្រើទូរសព្ទរបស់អ្នកបានដដែល ប៉ុន្តែវានឹងដំណើរការយឺតជាងមុន។\n\nបន្ទាប់ពីទូរសព្ទរបស់អ្នកត្រជាក់ជាងមុនហើយ វានឹងដំណើរការដូចធម្មតា។"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"មើលជំហានថែទាំ"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ដកឧបករណ៍របស់អ្នក"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ឧបករណ៍របស់អ្នកកំពុងឡើងកម្ដៅនៅជិតរន្ធសាកថ្ម។ ប្រសិនបើឧបករណ៍នេះត្រូវបានភ្ជាប់ទៅឆ្នាំងសាក ឬគ្រឿងបរិក្ខារ USB សូមដកវា និងមានការប្រុងប្រយ័ត្ន ដោយសារខ្សែក៏អាចក្ដៅផងដែរ។"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 5fa9464..437f406 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ಪವರ್ ಮೆನು"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ಲಾಕ್ ಪರದೆ"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ಫೋನ್ ಬಿಸಿಯಾಗಿದ್ದರಿಂದ ಆಫ್ ಆಗಿದೆ"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"ನಿಮ್ಮ ಫೋನ್ ಈಗ ಎಂದಿನಂತೆ ರನ್ ಆಗುತ್ತಿದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ನಿಮ್ಮ ಫೋನ್ ತುಂಬಾ ಬಿಸಿಯಾಗಿತ್ತು, ತಣ್ಣಗಾಗಲು ಅದು ತಾನಾಗಿ ಆಫ್ ಆಗಿದೆ. ಈಗ ನಿಮ್ಮ ಫೋನ್ ಎಂದಿನಂತೆ ಕೆಲಸ ಮಾಡುತ್ತಿದೆ.\n\nನಿಮ್ಮ ಫೋನ್ ಬಿಸಿಯಾಗಲು ಕಾರಣಗಳು:\n • ಹೆಚ್ಚು ಸಂಪನ್ಮೂಲ ಉಪಯೋಗಿಸುವ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಬಳಕೆ (ಉದಾ, ಗೇಮಿಂಗ್, ವೀಡಿಯೊ/ನ್ಯಾವಿಗೇಶನ್ ಅಪ್ಲಿಕೇಶನ್ಗಳು)\n • ದೊಡ್ಡ ಫೈಲ್ಗಳ ಡೌನ್ಲೋಡ್ ಅಥವಾ ಅಪ್ಲೋಡ್\n • ಅಧಿಕ ಉಷ್ಣಾಂಶದಲ್ಲಿ ಫೋನಿನ ಬಳಕೆ"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ಫೋನ್ ಬಿಸಿಯಾಗುತ್ತಿದೆ"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸಲಾಗುತ್ತದೆ\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"ನಿಮ್ಮ ಫೋನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ, ಆದರೆ ಇದು ನಿಧಾನವಾಗಿರಬಹುದು.\n\nಒಮ್ಮೆ ನಿಮ್ಮ ಫೋನ್ ತಣ್ಣಗಾದ ನಂತರ ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್ಪ್ಲಗ್ ಮಾಡಿ"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ಚಾರ್ಜಿಂಗ್ ಪೋರ್ಟ್ ಸಮೀಪದಲ್ಲಿ ನಿಮ್ಮ ಸಾಧನವು ಬಿಸಿಯಾಗುತ್ತಿದೆ. ಅದನ್ನು ಚಾರ್ಜರ್ ಅಥವಾ USB ಪರಿಕರಕ್ಕೆ ಕನೆಕ್ಟ್ ಮಾಡಿದ್ದರೆ, ಅದನ್ನು ಅನ್ಪ್ಲಗ್ ಮಾಡಿ ಹಾಗೂ ಕೇಬಲ್ ಕೂಡ ಬಿಸಿಯಾಗಿರಬಹುದು ಆದ್ದರಿಂದ ಎಚ್ಚರಿಕೆ ವಹಿಸಿ."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index eb4afbb..9916951 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB 사용"</string>
<string name="learn_more" msgid="4690632085667273811">"자세히 알아보기"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"스크린샷"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"잠금 해제 연장 사용 중지됨"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"잠금 해제 유지 사용 중지됨"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"이미지 보냄"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"캡쳐화면 저장 중..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"직장 프로필에 스크린샷 저장 중…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"전원 메뉴"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"잠금 화면"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"발열로 인해 휴대전화 전원이 종료됨"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"이제 휴대전화가 정상적으로 작동합니다.\n자세히 알아보려면 탭하세요."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"휴대전화가 과열되어 온도를 낮추기 위해 전원이 종료되었습니다. 지금은 휴대전화가 정상적으로 실행 중입니다.\n\n휴대전화가 과열되는 이유는 다음과 같습니다.\n • 리소스를 많이 사용하는 앱 사용(예: 게임, 동영상 또는 내비게이션 앱)\n • 대용량 파일을 다운로드 또는 업로드\n • 온도가 높은 곳에서 휴대폰 사용"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"해결 방법 확인하기"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"휴대전화 온도가 높음"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다.\n자세히 알아보려면 탭하세요."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"휴대전화 온도를 자동으로 낮추려고 시도합니다. 휴대전화를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n휴대전화 온도가 낮아지면 정상적으로 작동됩니다."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"해결 방법 확인하기"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"기기 분리하기"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"기기의 충전 포트 주변 온도가 상승하고 있습니다. 충전기나 USB 액세서리가 연결된 상태라면 분리하세요. 이때 케이블도 뜨거울 수 있으므로 주의하시기 바랍니다."</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index c8f6c37..aaec2cd 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB’ни иштетүү"</string>
<string name="learn_more" msgid="4690632085667273811">"Кененирээк"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"\"Кулпуну ачуу\" функциясы өчүрүлдү"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Кулпуланбаган режим өчүрүлдү"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сүрөт жөнөттү"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншот сакталууда..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Скриншот жумуш профилине сакталууда…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Кубат баскычынын менюсу"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Кулпуланган экран"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон ысыгандыктан өчүрүлдү"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефонуңуз кадимкидей иштеп жатат.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефонуңуз өтө ысып кеткендиктен, аны муздатуу үчүн өчүрүлдү. Эми телефонуңуз кадимкидей иштеп жатат.\n\nТелефонуңуз төмөнкү шарттарда ысып кетиши мүмкүн:\n • Ашыкча ресурс короткон колдонмолорду (оюндар, видео же чабыттоо колдонмолору) пайдалансаңыз \n • Ири көлөмдөгү файлдарды жүктөп алсаңыз же берсеңиз\n • Телефонуңузду жогорку температураларда пайдалансаңыз"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Тейлөө кадамдарын көрүңүз"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Телефонуңуз ысып баратат"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон сууганча айрым элементтердин иши чектелген.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонуңуз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТелефонуңуз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Тейлөө кадамдарын көрүңүз"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Түзмөктү сууруп коюңуз"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Түзмөгүңүздүн кубаттоо порту жылып баратат. Эгер түзмөгүңүз кубаттагычка же USB кабелине туташып турса, аны сууруп коюңуз. Абайлаңыз, кабель да жылуу болушу мүмкүн."</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index da4547b..1681f7a 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -35,6 +35,9 @@
<dimen name="volume_tool_tip_top_margin">12dp</dimen>
<dimen name="volume_row_slider_height">128dp</dimen>
+ <!-- width of ImmersiveModeConfirmation (-1 for match_parent) -->
+ <dimen name="immersive_mode_cling_width">380dp</dimen>
+
<dimen name="controls_activity_view_top_offset">25dp</dimen>
<dimen name="biometric_dialog_button_negative_max_width">140dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 756444d..0306fc9 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"ເປີດໃຊ້ USB"</string>
<string name="learn_more" msgid="4690632085667273811">"ສຶກສາເພີ່ມເຕີມ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ພາບໜ້າຈໍ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ຂະຫຍາຍການປົດລັອກຖືກປິດການນຳໃຊ້ແລ້ວ"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ຄຸນສົມບັດການປົດລັອກດົນຂຶ້ນຖືກປິດການນຳໃຊ້ແລ້ວ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ສົ່ງຮູບແລ້ວ"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ກຳລັງບັນທຶກຮູບໜ້າຈໍໃສ່ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ເມນູເປີດປິດ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ໜ້າຈໍລັອກ"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ປິດໂທລະສັບເນື່ອງຈາກຮ້ອນເກີນໄປ"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"ໂທລະສັບຂອງທ່ານຕອນນີ້ເຮັດວຽກປົກກະຕິແລ້ວ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ໂທລະສັບຂອງທ່ານຮ້ອນເກີນໄປ, ດັ່ງນັ້ນມັນຈຶ່ງຖືກປິດໄວ້ເພື່ອໃຫ້ເຢັນກ່ອນ. ໂທລະສັບຂອງທ່ານຕອນນີ້ເຮັດວຽກປົກກະຕິແລ້ວ.\n\nໂທລະສັບຂອງທ່ານອາດຮ້ອນຫາກວ່າທ່ານ:\n • ໃຊ້ແອັບທີ່ກິນຊັບພະຍາກອນຫຼາຍ (ເຊັ່ນ: ເກມ, ວິດີໂອ ຫຼື ແອັບການນຳທາງ)\n • ດາວໂຫລດ ຫຼື ອັບໂຫລດຮູບພາບຂະໜາດໃຫຍ່\n • ໃຊ້ໂທລະສັບຂອງທ່ານໃນບ່ອນທີ່ມີອຸນຫະພູມສູງ"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ໂທລະສັບກຳລັງຮ້ອນຂຶ້ນ"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ຄຸນສົມບັດບາງຢ່າງຖືກຈຳກັດໄວ້ໃນເວລາຫຼຸດອຸນຫະພູມຂອງໂທລະສັບ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"ໂທລະສັບຂອງທ່ານຈະພະຍາຍາມລົດອຸນຫະພູມລົງ. ທ່ານຍັງຄົງສາມາດໃຊ້ໂທລະສັບຂອງທ່ານໄດ້ຢູ່, ແຕ່ມັນຈະເຮັດວຽກຊ້າລົງ.\n\nເມື່ອໂທລະສັບຂອງທ່ານບໍ່ຮ້ອນຫຼາຍແລ້ວ, ມັນຈະກັບມາເຮັດວຽກຕາມປົກກະຕິ."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ຖອດອຸປະກອນຂອງທ່ານອອກ"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ອຸປະກອນຂອງທ່ານຈະອຸ່ນຂຶ້ນເມື່ອຢູ່ໃກ້ຊ່ອງສາກໄຟ. ຫາກມັນເຊື່ອມຕໍ່ຫາສາຍສາກ ຫຼື ອຸປະກອນເສີມ USB ໃດໜຶ່ງຢູ່, ໃຫ້ຖອດມັນອອກ ແລະ ລະວັງເນື່ອງຈາກສາຍກໍອາດຈະອຸ່ນເຊັ່ນກັນ."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ff745b5..8548a24 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Įjungimo meniu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Užrakinimo ekranas"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefonas išjungt., nes įkaito"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonas dabar veikia normaliai.\nPalietę gausite daugiau informacijos"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonas per daug įkaito, todėl buvo išj., kad atvėstų. Dabar telefonas veikia įprastai.\n\nTelefonas gali per daug įkaisti, jei:\n • esate įjungę daug išteklių naudoj. progr. (pvz., žaidimų, vaizdo įr. arba navig. progr.);\n • atsis. arba įkeliate didelius failus;\n • telefoną naudojate aukštoje temper."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Žr. priežiūros veiksmus"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefonas kaista"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta.\nPalietę gausite daugiau informacijos"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonas automatiškai bandys atvėsti. Telefoną vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai telefonas atvės, jis veiks įprastai."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Žr. priežiūros veiksmus"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Atjunkite įrenginį"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Įrenginys kaista šalia įkrovimo prievado. Jei jis prijungtas prie kroviklio ar USB priedo, atjunkite jį ir patikrinkite, nes laidas taip pat gali būti įkaitęs."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c8c18fb..79f73b6 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Barošanas izvēlne"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Bloķēšanas ekrāns"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Tālrunis izslēgts karstuma dēļ"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Tagad jūsu tālrunis darbojas normāli.\nPieskarieties, lai uzzinātu vairāk."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Jūsu tālrunis bija pārkarsis un tika izslēgts. Tagad tas darbojas normāli.\n\nTālrunis var sakarst, ja:\n • tiek izmantotas lietotnes, kas patērē daudz enerģijas (piem., spēles, video lietotnes vai navigācija);\n • tiek lejupielādēti/augšupielādēti lieli faili;\n • tālrunis tiek lietots augstā temperatūrā."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Skatīt apkopes norādījumus"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Tālrunis kļūst silts"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Dažas funkcijas ir ierobežotas, kamēr notiek tālruņa atdzišana.\nPieskarieties, lai uzzinātu vairāk."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Jūsu tālrunis automātiski mēģinās atdzist. Jūs joprojām varat izmantot tālruni, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz tālrunis būs atdzisis, tas darbosies normāli."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Skatīt apkopes norādījumus"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Atvienojiet savu ierīci"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Jūsu ierīce uzkarst, atrodoties uzlādes pieslēgvietas tuvumā. Ja ierīce ir pievienota lādētājam vai USB piederumam, uzmanīgi atvienojiet to, jo arī vads var būt uzkarsis."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index e429979..b8829c6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени на копчето за вклучување"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заклучен екран"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефонот се исклучи поради загреаност"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Сега телефонот работи нормално.\nДопрете за повеќе информации"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефонот беше премногу загреан, така што се исклучи за да се олади. Сега работи нормално.\n\nТелефонот може премногу да се загрее ако:\n • користите апликации што работат со многу ресурси (како што се, на пример, апликациите за видеа, навигација или игри)\n • преземате или поставувате големи датотеки\n •го користите телефонот на високи температури"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Прикажи ги чекорите за грижа за уредот"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Телефонот се загрева"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Некои функции се ограничени додека телефонот се лади.\nДопрете за повеќе информации"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонот автоматски ќе се обиде да се олади. Вие сепак ќе може да го користите, но тој може да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Прикажи ги чекорите за грижа за уредот"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Исклучете го уредот од кабел"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Вашиот уред се загрева во близина на портата за полнење. Ако е поврзан со полнач или USB-додаток, исклучете го од него и внимавајте бидејќи кабелот може да е топол."</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 83d045e..f8c14e6 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="learn_more" msgid="4690632085667273811">"കൂടുതലറിയുക"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"സ്ക്രീൻഷോട്ട്"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock പ്രവർത്തനരഹിതമാക്കി"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"എക്സ്റ്റൻഡ് അൺലോക്ക് പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ഔദ്യോഗിക പ്രൊഫൈലിലേക്ക് സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"പവർ മെനു"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ലോക്ക് സ്ക്രീൻ"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ചൂട് കൂടിയതിനാൽ ഫോൺ ഓഫാക്കി"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"നിങ്ങളുടെ ഫോൺ ഇപ്പോൾ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കുന്നു.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ഫോൺ ചൂടായിരിക്കുന്നതിനാൽ തണുക്കാൻ ഓഫാക്കിയിരിക്കുന്നു. ഫോൺ ഇപ്പോൾ സാധാരണഗതിയിൽ പ്രവർത്തിക്കുന്നു.\n\nഫോണിന് ചൂട് കൂടാൻ കാരണം:\n • ഗെയിമിംഗ്, വീഡിയോ അല്ലെങ്കിൽ നാവിഗേഷൻ തുടങ്ങിയ റിസോഴ്സ്-ഇന്റൻസീവായ ആപ്പുകൾ ഉപയോഗിക്കുന്നത്\n • വലിയ ഫയലുകൾ അപ്ലോഡോ ഡൗൺലോഡോ ചെയ്യുന്നത്\n • ഉയർന്ന താപനിലയിൽ ഫോൺ ഉപയോഗിക്കുന്നത്"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ഫോൺ ചൂടായിക്കൊണ്ടിരിക്കുന്നു"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ഫോൺ തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തപ്പെടും.\nകൂടുതൽ വിവരങ്ങൾക്ക് ടാപ്പ് ചെയ്യുക"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"നിങ്ങളുടെ ഫോൺ സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഫോൺ ഉപയോഗിക്കാമെങ്കിലും പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കും.\n\nതണുത്തുകഴിഞ്ഞാൽ, ഫോൺ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കും."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"പരിപാലന നിർദ്ദേശങ്ങൾ കാണുക"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ഉപകരണം അൺപ്ലഗ് ചെയ്യുക"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ചാർജിംഗ് പോർട്ടിന് സമീപം നിങ്ങളുടെ ഉപകരണം ചൂടാകുന്നുണ്ട്. ഇത് ചാർജറിലേക്കോ USB ആക്സസറിയിലേക്കോ കണക്റ്റ് ചെയ്തിട്ടുണ്ടെങ്കിൽ അൺപ്ലഗ് ചെയ്യുക, കേബിളും ചൂടായിരിക്കാമെന്നതിനാൽ ശ്രദ്ധിക്കണം."</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 98d0ddd..ceb8782 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB-г идэвхжүүлэх"</string>
<string name="learn_more" msgid="4690632085667273811">"Нэмэлт мэдээлэл авах"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Дэлгэцийн зураг дарах"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock-г идэвхгүй болгосон"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Түгжээгүй байлгахыг идэвхгүй болгосон"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"зураг илгээсэн"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Дэлгэцийн агшинг хадгалж байна…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Дэлгэцийн агшныг ажлын профайлд хадгалж байна…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Асаах/унтраах цэс"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Түгжээтэй дэлгэц"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Халснаас үүдэн утас унтарсан"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Таны утас одоо хэвийн ажиллаж байна.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Таны утас хэт халсан тул хөргөхөөр унтраасан болно. Таны утас одоо хэвийн ажиллаж байна.\n\nХэрэв та дараахыг хийвэл таны утас хэт халж болзошгүй:\n • Их хэмжээний нөөц хэрэглээний апп (тоглоом, видео эсвэл шилжилтийн апп зэрэг)\n • Багтаамж ихтэй файл татах, байршуулах\n • Утсаа өндөр температурт ашиглах"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Хянамж болгоомжийн алхмыг харах"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Утас халж эхэлж байна"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Утсыг хөрөх үед зарим онцлогийг хязгаарлана.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Таны утас автоматаар хөрөх болно. Та утсаа ашиглаж болох хэдий ч удаан ажиллаж болзошгүй.\n\nТаны утас хөрсний дараагаар хэвийн ажиллана."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Хянамж болгоомжийн алхмыг харах"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Төхөөрөмжөө салгана уу"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Таны төхөөрөмж цэнэглэх портын ойролцоо халж байна. Хэрэв төхөөрөмжийг цэнэглэгч эсвэл USB дагалдах хэрэгсэлд холбосон бол төхөөрөмжийг салгаж, кабель нь халуун байж болзошгүй тул болгоомжтой байгаарай."</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 6547cfe..ba45d53 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पॉवर मेनू"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g> पेज"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्क्रीन"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"तापल्यामुळे फोन बंद झाला"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"तुमचा फोन आता नेहमीप्रमाणे काम करत आहे.\nअधिक माहितीसाठी टॅप करा"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"तुमचा फोन खूप तापलाय, म्हणून तो थंड होण्यासाठी बंद झाला आहे. तुमचा फोन आता व्यवस्थित सुरू आहे.\n\nतुम्ही असे केल्यास तुमचा फोन खूप तापेल:\n •संसाधन केंद्रित अॅप वापरणे (गेमिंग, व्हिडिओ किंवा नेव्हिगेशन अॅप यासारखे)\n •मोठ्या फाइल डाउनलोड किंवा अपलोड करणे\n •उच्च तापमानामध्ये तुमचा फोन वापरणे"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"काय काळजी घ्यावी ते पहा"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"फोन ऊष्ण होत आहे"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"फोन थंड होईपर्यंत काही वैशिष्ट्ये मर्यादित केली.\nअधिक माहितीसाठी टॅप करा"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"तुमचा फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही तुमचा फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nतुमचा फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"काय काळजी घ्यावी ते पहा"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"तुमचे डिव्हाइस अनप्लग करा"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"तुमचे डिव्हाइस हे चार्जिंग पोर्टच्या जवळ गरम होत आहे. हे चार्जर किंवा USB अॅक्सेसरी यांच्याशी कनेक्ट केलेले असल्यास, ते अनप्लग करा आणि काळजी घ्या कारण केबलदेखील गरम असू शकते."</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 3d1a222..e28ea01 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Dayakan USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Ketahui lebih lanjut"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Tangkapan skrin"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Lanjutkan Buka Kunci dilumpuhkan"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Buka Kunci Berterusan dilumpuhkan"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Menyimpan tangkapan skrin ke profil kerja…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu kuasa"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Kunci skrin"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon dimatikan kerana panas"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon anda kini berjalan seperti biasa.\nKetik untuk mendapatkan maklumat lanjut"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon anda terlalu panas, jadi telefon itu telah dimatikan untuk menyejuk. Sekarang, telefon anda berjalan seperti biasa.\n\nTelefon anda mungkin menjadi terlalu panas jika anda:\n • Menggunakan apl intensif sumber (seperti permainan, video atau apl navigasi)\n • Memuat turun atau memuat naik fail besar\n • Menggunakan telefon anda dalam suhu tinggi"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah penjagaan"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon semakin panas"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Sesetengah ciri adalah terhad semasa telefon menyejuk.\nKetik untuk mendapatkan maklumat lanjut"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan telefon itu tetapi telefon tersebut mungkin berjalan lebih perlahan.\n\nSetelah telefon anda sejuk, telefon itu akan berjalan seperti biasa."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah penjagaan"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Cabut palam peranti anda"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Peranti anda menjadi panas berdekatan port pengecasan. Jika peranti anda disambungkan ke pengecas atau aksesori USB, cabut palam peranti dan berhati-hati kerana kabel juga mungkin panas."</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 34f580a..5bcd5a0 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB ကို ဖွင့်ရန်"</string>
<string name="learn_more" msgid="4690632085667273811">"ပိုမိုလေ့လာရန်"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"‘တိုးချဲ့ဖွင့်ခြင်း’ ပိတ်ထားသည်"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"‘လော့ခ်ဖွင့်ချိန်တိုးခြင်း’ ပိတ်ထားသည်"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ပုံပို့ထားသည်"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား သိမ်းဆည်းပါမည်"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"အလုပ်ပရိုဖိုင်တွင် ဖန်သားပြင်ဓာတ်ပုံ သိမ်းနေသည်…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ပါဝါမီနူး"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"လော့ခ်ချထားချိန် မျက်နှာပြင်"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"အပူရှိန်ကြောင့်ဖုန်းပိတ်ထားသည်"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"သင့်ဖုန်းသည် ယခု ပုံမှန်အလုပ်လုပ်နေပါပြီ။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"သင့်ဖုန်းအလွန်ပူနေသည့်အတွက် အေးသွားစေရန် ပိတ်ထားပါသည်။ ယခုပုံမှန် အလုပ်လုပ်ပါပြီ။\n\nအောက်ပါတို့ကိုသုံးလျှင် ပူလာပါမည်-\n • အရင်းအမြစ်များသောအက်ပ်ကို သုံးခြင်း (ဥပမာ ဂိမ်းကစားခြင်း၊ ဗီဒီယိုကြည့်ခြင်း (သို့) လမ်းညွှန်အက်ပ်)\n • ကြီးမားသောဖိုင်များ ဒေါင်းလုဒ် (သို့) အပ်လုဒ်လုပ်ခြင်း\n • အပူရှိန်မြင့်သောနေရာတွင် သုံးခြင်း"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ဖုန်း ပူနွေးလာပါပြီ"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ဖုန်းကို အေးအောင်ပြုလုပ်နေစဉ်တွင် အချို့ဝန်ဆောင်မှုများကို ကန့်သတ်ထားပါသည်။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"သင့်ဖုန်းသည် အလိုအလျောက် ပြန်အေးသွားပါလိမ့်မည်။ ဖုန်းကို အသုံးပြုနိုင်ပါသေးသည် သို့သော် ပိုနှေးနိုင်ပါသည်။\n\nသင့်ဖုန်း အေးသွားသည်နှင့် ပုံမှန်အတိုင်း ပြန်အလုပ်လုပ်ပါလိမ့်မည်။"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"သင့်စက်ကို ပလတ်ဖြုတ်ပါ"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"သင့်စက်သည် အားသွင်းပို့တ်အနီးတွင် ပူနွေးလာသည်။ ၎င်းကို အားသွင်းကိရိယာ (သို့) USB ဆက်စပ်ပစ္စည်းနှင့် ချိတ်ဆက်ထားပါက ပလတ်ဖြုတ်ပါ။ ကြိုးကလည်း ပူနွေးနေနိုင်သဖြင့် ဂရုပြုပါ။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a6111d9..755ee81 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Slå på USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Finn ut mer"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock er slått av"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Hold ulåst er slått av"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Lagrer skjermdumpen i jobbprofilen …"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Av/på-meny"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskjerm"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon ble slått av pga varme"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonen kjører nå som normalt.\nTrykk for å se mer informasjon"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonen din var for varm, så den ble slått av for å kjøles ned. Telefonen din kjører nå som normalt.\n\nTelefonen kan blir for varm hvis du:\n • bruker ressurskrevende apper (for eksempel spill-, video- eller navigeringsapper)\n • laster store filer opp eller ned\n • bruker telefonen ved høy temperatur"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se vedlikeholdstrinnene"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefonen begynner å bli varm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Enkelte funksjoner er begrenset mens telefonen kjøles ned.\nTrykk for å se mer informasjon"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonen din kommer til å prøve å kjøle seg ned automatisk. Du kan fremdeles bruke telefonen, men den kjører muligens saktere.\n\nTelefonen kommer til å kjøre som normalt, når den har kjølt seg ned."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se vedlikeholdstrinnene"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Koble fra enheten"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Enheten begynner å bli varm nær ladeporten. Hvis den er koblet til en lader eller et USB-tilbehør, må du koble den fra. Vær forsiktig da kabelen også kan være varm."</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 610e28b..d1445e1 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB सक्षम पार्नुहोस्"</string>
<string name="learn_more" msgid="4690632085667273811">"थप जान्नुहोस्"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock अफ गरिएको छ"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"एक्स्टेन्ड अनलक अफ गरिएको छ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"कार्य प्रोफाइलमा स्क्रिनसट सेभ गरिँदै छ…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"पावर मेनु"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"लक स्क्रिन"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"फोन अति नै तातिएकाले चिसिन बन्द भयो"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"तपाईंको फोन अहिले सामान्य रूपमा चलिरहेको छ।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"तपाईंको फोन अति नै तातिएकाले चिसिन बन्द भयो। तपाईंको फोन अब सामान्य ढंगले चल्दै छ।\n\nतपाईंले निम्न कुराहरू गर्नुभयो भने तपाईंको फोन अत्यन्त तातो हुनसक्छ:\n • धेरै संसाधन खपत गर्ने एपहरूको प्रयोग (जस्तै गेमिङ, भिडियो वा नेभिगेसन एपहरू)\n • ठूला फाइलहरूको डाउनलोड वा अपलोड\n • उच्च तापक्रममा फोनको प्रयोग"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"फोन तातो भइरहेको छ"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"फोन नचिस्सिँदासम्म केही सुविधाहरू उपलब्ध हुने छैनन्।\nथप जानकारीका लागि ट्याप गर्नुहोस्"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"तपाईंको फोन स्वतः चिसो हुने प्रयास गर्ने छ। तपाईं अझै पनि आफ्नो फोनको प्रयोग गर्न सक्नुहुन्छ तर त्यो अझ ढिलो चल्न सक्छ।\n\nचिसो भएपछि तपाईंको फोन सामान्य गतिमा चल्नेछ।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिभाइसको हेरचाह गर्ने तरिका हेर्नुहोस्"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"डिभाइस बिजुलीको स्रोतबाट निकाल्नुहोस्"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"तपाईंको डिभाइसको चार्जिङ पोर्टतिरको भाग तातीरहेको छ। तपाईंको डिभाइस चार्जर वा USB एक्सेसरीमा जोडिएको गरिएको छ भने त्यसलाई निकाल्नुहोस्। यसका साथै सो केबल तातो हुन सक्ने भएकाले ख्याल गर्नुहोला।"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3f7f829..932889b 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Aan/uit-menu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Vergrendelscherm"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefoon uitgezet wegens hitte"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Je telefoon functioneert nu weer zoals gebruikelijk.\nTik voor meer informatie"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Je telefoon was te warm en is uitgezet om af te koelen. Je telefoon presteert nu weer zoals gebruikelijk.\n\nJe telefoon kan warm worden als je:\n • bronintensieve apps gebruikt (zoals game-, video-, of navigatie-apps),\n • grote bestanden up- of downloadt,\n • je telefoon gebruikt bij hoge temperaturen."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Onderhoudsstappen bekijken"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"De telefoon wordt warm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt.\nTik voor meer informatie"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Je telefoon probeert automatisch af te koelen. Je kunt je telefoon nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de telefoon is afgekoeld, werkt deze weer normaal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Onderhoudsstappen bekijken"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Je apparaat loskoppelen"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Je apparaat wordt warm in de buurt van de oplaadpoort. Als het apparaat is aangesloten op een oplader of USB-poort, koppel je het los. Wees voorzichtig: de kabel kan warm zijn."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 3728d5a..8061fd6 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="learn_more" msgid="4690632085667273811">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlockକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ଏକ୍ସଟେଣ୍ଡ ଅନଲକକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ୱାର୍କ ପ୍ରୋଫାଇଲରେ ସ୍କ୍ରିନସଟ ସେଭ କରାଯାଉଛି…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ପାୱାର ମେନୁ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ପୃଷ୍ଠା <xliff:g id="ID_1">%1$d</xliff:g> ମୋଟ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ଲକ ସ୍କ୍ରିନ"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ଗରମ ହେତୁ ଫୋନ୍ ଅଫ୍ କରିଦିଆଗଲା"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"ଆପଣଙ୍କ ଫୋନ୍ ବର୍ତ୍ତମାନ ସାମାନ୍ୟ ରୂପେ ଚାଲୁଛି।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ଆପଣଙ୍କ ଫୋନ୍ ବହୁତ ଗରମ ଥିଲା, ତେଣୁ ଏହାକୁ ଥଣ୍ଡା କରାଯିବାକୁ ଅଫ୍ କରିଦିଆଗଲା। ଆପଣଙ୍କ ଫୋନ୍ ବର୍ତ୍ତମାନ ସାମାନ୍ୟ ଅବସ୍ଥାରେ ଚାଲୁଛି।\n\nଆପଣଙ୍କ ଫୋନ୍ ଅଧିକ ଗରମ ହୋଇଯାଇପାରେ ଯଦି ଆପଣ:\n • ରିସୋର୍ସ-ଇଣ୍ଟେନସିଭ୍ ଆପ୍ (ଯେପରିକି ଗେମିଙ୍ଗ, ଭିଡିଓ, କିମ୍ବା ନେଭିଗେସନ୍ ଆପ୍) ବ୍ୟବହାର କରନ୍ତି\n • ବଡ ଫାଇଲ୍ ଡାଉନଲୋଡ କିମ୍ବା ଅପଲୋଡ୍ କରନ୍ତି\n • ଅଧିକ ତାପମାତ୍ରାରେ ଆପଣଙ୍କ ଫୋନ୍ ବ୍ୟବହାର କରନ୍ତି"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ଫୋନ୍ ଗରମ ହୋଇଯାଉଛି"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ଫୋନ୍ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର୍ ଠିକ ଭାବେ କାମ କରିନଥାଏ।\nଅଧିକ ସୂଚନା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"ଆପଣଙ୍କ ଫୋନ୍ ସ୍ୱଚାଳିତ ଭାବେ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ତଥାପି ନିଜ ଫୋନ୍ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଫୋନ୍ ଥଣ୍ଡା ହୋଇଯିବାପରେ, ଏହା ସାମାନ୍ୟ ଭାବେ ଚାଲିବ।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ଯତ୍ନ ନେବା ପାଇଁ ଷ୍ଟେପଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ଆପଣଙ୍କ ଡିଭାଇସକୁ ଅନପ୍ଲଗ କରନ୍ତୁ"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ଚାର୍ଜିଂ ପୋର୍ଟ ନିକଟରେ ଆପଣଙ୍କ ଡିଭାଇସ ଗରମ ହୋଇଯାଉଛି। ଯଦି ଏହା ଏକ ଚାର୍ଜର କିମ୍ବା USB ଆକସେସୋରୀ ସହ କନେକ୍ଟ କରାଯାଇଥାଏ ତେବେ ଏହାକୁ ଅନପ୍ଲଗ କରନ୍ତୁ ଏବଂ ଧ୍ୟାନ ରଖନ୍ତୁ କାରଣ କେବୁଲ ମଧ୍ୟ ଗରମ ହୋଇପାରେ।"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index bb511e3..0f3ef6a 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB ਚਾਲੂ ਕਰੋ"</string>
<string name="learn_more" msgid="4690632085667273811">"ਹੋਰ ਜਾਣੋ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ਐਕਸਟੈਂਡ ਅਣਲਾਕ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"ਪਾਵਰ ਮੀਨੂ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">" ਲਾਕ ਸਕ੍ਰੀਨ"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"ਗਰਮ ਹੋਣ ਕਾਰਨ ਫ਼ੋਨ ਬੰਦ ਹੋ ਗਿਆ"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\nਵਧੇਰੇ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">\n"ਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਸੀ, ਇਸ ਲਈ ਇਹ ਠੰਡਾ ਹੋਣ ਵਾਸਤੇ ਬੰਦ ਹੋ ਗਿਆ ਸੀ। ਤੁਹਾਡਾ ਫ਼ੋਨ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\n\nਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਹੋ ਸਕਦਾ ਹੈ ਜੇ:\n • ਤੁਸੀਂ ਸਰੋਤਾਂ ਦੀ ਵੱਧ ਵਰਤੋਂ ਵਾਲੀਆਂ ਐਪਾਂ (ਜਿਵੇਂ ਗੇਮਿੰਗ, ਵੀਡੀਓ, ਜਾਂ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਐਪਾਂ) ਵਰਤਦੇ ਹੋ • ਵੱਡੀਆਂ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਜਾਂ ਅੱਪਲੋਡ ਕਰਦੇ ਹੋ\n • ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਉੱਚ ਤਾਪਮਾਨਾਂ ਵਿੱਚ ਵਰਤਦੇ ਹੋ"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ਫ਼ੋਨ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ਫ਼ੋਨ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਤ ਹੁੰਦੀਆਂ ਹਨ।\nਵਧੇਰੇ ਜਾਣਕਾਰੀ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਵੈਚਲਿਤ ਰੂਪ ਵਿੱਚ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰੰਤੂ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ ਵਧੇਰੇ ਹੌਲੀ ਚੱਲੇ।\n\nਇੱਕ ਵਾਰ ਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਧਾਰਨ ਤੌਰ \'ਤੇ ਚੱਲੇਗਾ।"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਪਲੱਗ ਕਰੋ"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਚਾਰਜਿੰਗ ਪੋਰਟ ਦੇ ਨੇੜੇ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ। ਜੇ ਇਹ ਕਿਸੇ ਚਾਰਜਰ ਜਾਂ USB ਐਕਸੈਸਰੀ ਨਾਲ ਕਨੈਕਟ ਹੈ, ਤਾਂ ਇਸਨੂੰ ਅਣਪਲੱਗ ਕਰੋ ਅਤੇ ਸਾਵਧਾਨ ਰਹੋ, ਕਿਉਂਕਿ ਕੇਬਲ ਵੀ ਗਰਮ ਹੋ ਸਕਦੀ ਹੈ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 5dcdd7e..757ffcd 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Włącz USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Więcej informacji"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Zrzut ekranu"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Wyłączono Extend Unlock"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Wyłączono rozszerzone odblokowanie"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Zapisuję zrzut ekranu w profilu służbowym…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu zasilania"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran blokady"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon wyłączony: przegrzanie"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon działa teraz normalnie\nKliknij, by dowiedzieć się więcej"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon był zbyt gorący i wyłączył się, by obniżyć temperaturę. Urządzenie działa teraz normalnie.\n\nTelefon może się przegrzać, gdy:\n • Używasz aplikacji zużywających dużo zasobów (np. gier, nawigacji czy odtwarzaczy filmów)\n • Pobierasz lub przesyłasz duże pliki\n • Używasz telefonu w wysokiej temperaturze"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobacz instrukcję postępowania"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon się nagrzewa"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone\nKliknij, by dowiedzieć się więcej"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale telefon może działać wolniej.\n\nGdy temperatura się obniży, telefon będzie działał normalnie."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobacz instrukcję postępowania"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Odłącz urządzenie"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Urządzenie za bardzo się nagrzewa w okolicy gniazda ładowania. Jeśli jest podłączone do ładowarki albo akcesorium USB, odłącz je. Uważaj, bo kabel również może być nagrzany."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 3ac3692..4ee6bd2 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Ativar USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Saiba mais"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock desativado"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desbloqueio extra desativado"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Salvando captura de tela no perfil de trabalho…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"O smartphone foi desligado devido ao aquecimento"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"O smartphone está funcionando normalmente agora.\nToque para saber mais"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O smartphone estava muito quente e foi desligado para resfriar. Agora, ele está sendo executado normalmente.\n\nO smartphone pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer o download ou upload de arquivos grandes;\n • usar o smartphone em temperaturas altas."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"O smartphone está esquentando"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconecte seu dispositivo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Seu dispositivo está ficando quente perto da porta de carregamento. Desconecte qualquer carregador ou acessório USB que esteja conectado, mas tome cuidado, porque o cabo também pode estar quente."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 6d54a64..f16b027 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Ativar USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Saiba mais"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de ecrã"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desbloqueio prolongado desativado"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desbloqueio extra desativado"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"A guardar captura de ecrã..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"A guardar captura de ecrã no perfil de trabalho…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu ligar/desligar"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ecrã de bloqueio"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telem. deslig. devido ao calor"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"O seu telemóvel já está a funcionar normalmente.\nToque para obter mais informações."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O telemóvel estava muito quente, por isso desligou-se para arrefecer. Agora funciona normalmente.\n\nO telemóvel pode sobreaquecer se:\n • Usar aplicações que utilizam mais recursos (jogos, vídeo ou aplicações de navegação)\n • Transferir ou carregar ficheiros grandes\n • Usar em altas temperaturas"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Veja os passos de manutenção"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"O telemóvel está a aquecer"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece.\nToque para obter mais informações."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"O telemóvel tenta arrefecer automaticamente. Pode continuar a utilizá-lo, mas este poderá funcionar mais lentamente.\n\nAssim que o telemóvel tiver arrefecido, funcionará normalmente."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Veja os passos de manutenção"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Desligue o dispositivo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"O dispositivo está a ficar quente perto da porta de carregamento. Se estiver ligado a um carregador ou um acessório USB, desligue-o e tenha cuidado, uma vez que o cabo também pode estar quente."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3ac3692..4ee6bd2 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Ativar USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Saiba mais"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock desativado"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Desbloqueio extra desativado"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Salvando captura de tela no perfil de trabalho…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menu liga/desliga"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"O smartphone foi desligado devido ao aquecimento"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"O smartphone está funcionando normalmente agora.\nToque para saber mais"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O smartphone estava muito quente e foi desligado para resfriar. Agora, ele está sendo executado normalmente.\n\nO smartphone pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer o download ou upload de arquivos grandes;\n • usar o smartphone em temperaturas altas."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"O smartphone está esquentando"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Desconecte seu dispositivo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Seu dispositivo está ficando quente perto da porta de carregamento. Desconecte qualquer carregador ou acessório USB que esteja conectado, mas tome cuidado, porque o cabo também pode estar quente."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d0764dd..e57eb5d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Activează USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Mai multe"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captură de ecran"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Funcția Extend Unlock este dezactivată"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Funcția Prelungirea deblocării este dezactivată"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Se salvează captura în profilul de serviciu…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meniul de pornire"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ecran de blocare"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefonul s-a oprit din cauza încălzirii"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Acum telefonul funcționează normal.\nAtinge pentru mai multe informații"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonul se încălzise prea mult și s-a oprit pentru a se răci. Acum telefonul funcționează normal.\n\nTelefonul s-ar putea încălzi prea mult dacă:\n • folosești aplicații care consumă multe resurse (de ex., jocuri, aplicații video/de navigare);\n • descarci/încarci fișiere mari;\n • folosești telefonul la temperaturi ridicate."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vezi pașii pentru îngrijire"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefonul se încălzește"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Anumite funcții sunt limitate în timp ce telefonul se răcește.\nAtinge pentru mai multe informații."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonul va încerca automat să se răcească. Îl poți folosi în continuare, dar e posibil să funcționeze mai lent.\n\nDupă ce se răcește, telefonul va funcționa normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vezi pașii pentru îngrijire"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Deconectează dispozitivul"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Dispozitivul se încălzește lângă portul de încărcare. Dacă este conectat la un încărcător sau accesoriu USB, deconectează-l și ai grijă, deoarece și cablul poate fi cald."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 91a8534..70f6e15 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Включить USB-порт"</string>
<string name="learn_more" msgid="4690632085667273811">"Подробнее"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Функция \"Отложить блокировку\" отключена"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Отложенная блокировка отключена"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Сохранение скриншота в рабочем профиле…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки питания"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокированный экран"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон выключился из-за перегрева"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Сейчас телефон работает нормально.\nНажмите, чтобы получить дополнительную информацию"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ваш телефон выключился из-за перегрева. Сейчас он работает нормально.\n\nВозможные причины перегрева телефона:\n • использование ресурсоемких игр и приложений, связанных с видео или навигацией);\n • скачивание или загрузка больших файлов;\n • высокая температура окружающей среды."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Подробнее о действиях при перегреве…"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Телефон нагревается"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Пока телефон не остынет, некоторые функции могут быть недоступны.\nНажмите, чтобы получить дополнительную информацию"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон остынет автоматически.\n\nОбратите внимание, что до тех пор он может работать медленнее, чем обычно."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Подробнее о действиях при перегреве…"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Отключите устройство"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Устройство нагревается в районе зарядного порта. Если оно подключено к зарядному или USB-устройству, отключите его. Будьте осторожны: кабель тоже мог нагреться."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 1efb408..b4dc0f2 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"බල මෙනුව"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"අගුලු තිරය"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"දුරකථනය රත් වීම නිසා ක්රියාවිරහිත කරන ලදී"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"ඔබගේ දුරකථනය දැන් සාමාන්ය ලෙස ධාවනය වේ.\nතව තතු සඳහා තට්ටු කරන්න"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ඔබේ දුරකථනය ඉතාම උණුසුම්ය, එම නිසා එය සිසිල් වීමට ක්රියාවිරහිත කරන ලදී. ධැන් ඔබේ දුරකථනය සාමාන්ය පරිදි ධාවනය වේ.\n\nඔබ පහත දේවල් සිදු කළහොත් ඔබේ දුරකථනය ඉතාම උණුසුම් විය හැකිය:\n • සම්පත්-දැඩි සත්කාරක යෙදුම් භාවිතය (ක්රීඩා, වීඩියෝ, හෝ සංචලන යෙදුම් යනාදී)\n • විශාල ගොනු බාගැනීම හෝ උඩුගත කිරීම\n • ඔබේ දුරකථනය අධික උෂ්ණත්වයේදී භාවිත කිරීම"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"රැකවරණ පියවර බලන්න"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"දුරකථනය උණුසුම් වෙමින්"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"දුරකථනය සිසිල් වන අතරතුර සමහර විශේෂාංග සීමිත විය හැකිය.\nතව තතු සඳහා තට්ටු කරන්න"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"ඔබගේ දුරකථනය ස්වයංක්රියව සිසිල් වීමට උත්සාහ කරනු ඇත. ඔබට තවම ඔබේ දුරකථනය භාවිත කළ හැකිය, නමුත් එය සෙමින් ධාවනය විය හැකිය.\n\nඔබේ දුරකථනය සිසිල් වූ පසු, එය සාමාන්ය ලෙස ධාවනය වනු ඇත."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"රැකවරණ පියවර බලන්න"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ඔබේ උපාංගය ගලවන්න"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ඔබේ උපාංගය ආරෝපණ කවුළුව අවට උණුසුම් වෙමින් පවතී. එය චාජරයකට හෝ USB උපාංගයකට සම්බන්ධ කර ඇත්නම්, එය ගලවා, කේබලය උණුසුම් විය හැකි බැවින් ප්රවේශම් වන්න."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b353293..802bd7a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Povoliť USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Ďalšie informácie"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snímka obrazovky"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Predĺžené odomknutie je vypnuté"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Rozšírené odomknutie je vypnuté"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ukladá sa snímka obrazovky do pracovného profilu…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Ponuka vypínača"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Uzamknutá obrazovka"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefón sa vypol z dôvodu prehriatia"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Teraz telefón funguje ako obvykle.\nViac sa dozviete po klepnutí."</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefón bol príliš horúci, preto sa vypol, aby vychladol. Teraz funguje ako obvykle.\n\nTelefón sa môže príliš zahriať v týchto prípadoch:\n • používanie náročných aplikácií (napr. hier, videí alebo navigácie);\n • sťahovanie alebo nahrávanie veľkých súborov;\n • používanie telefónu pri vysokých teplotách."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobraziť opatrenia"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Teplota telefónu stúpa"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu.\nViac sa dozviete po klepnutí."</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Váš telefón sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude telefón fungovať ako normálne."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobraziť opatrenia"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Odpojte zariadenie"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Zariadenie sa zahrieva pri nabíjacom porte. Ak je pripojené k nabíjačke alebo príslušenstvu USB, odpojte ho a dajte pozor, lebo môže byť horúci aj kábel."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 4dd753b..a303e20 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Omogoči USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Več o tem"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Posnetek zaslona"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Podaljšanje časa odklenjenosti je onemogočeno"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Razširjeno odklepanje je onemogočeno"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslal(-a) sliko"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Shranjevanje posnetka zaslona ..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Shranjevanje posnetka zaslona v delovni profil …"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Meni za vklop/izklop"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. stran od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Zaklenjen zaslon"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Tel. izklopljen zaradi vročine"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon zdaj deluje normalno.\nDotaknite se za več informacij"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon je bil prevroč, zato se je izklopil, da se ohladi. Zdaj normalno deluje.\n\nTelefon lahko postane prevroč ob:\n • uporabi aplikacij, ki intenzivno porabljajo sredstva (npr. za igranje iger, videoposnetke ali navigacijo)\n • prenosu ali nalaganju velikih datotek\n • uporabi telefona pri visokih temp."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Oglejte si navodila za ukrepanje"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon se segreva"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Nekatere funkcije bodo med ohlajanjem telefona omejene.\nDotaknite se za več informacij"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se telefon ohladi, bo zopet deloval kot običajno."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Oglejte si navodila za ukrepanje"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Odklopite napravo"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Naprava se segreva pri vratih za polnjenje. Če je priključena na polnilnik ali dodatek USB, ga odklopite in bodite tem previdni, saj je tudi kabel lahko topel."</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 475e799..4d0dcef 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Aktivizo USB-në"</string>
<string name="learn_more" msgid="4690632085667273811">"Mëso më shumë"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"\"Shkyçja e zgjeruar\" u çaktivizua"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"\"Shkyçja e zgjatur\" u çaktivizua"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Pamja e ekranit po ruhet te profili i punës…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyja e energjisë"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekrani i kyçjes"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefoni u fik për shkak të nxehtësisë"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefoni tani punon normalisht.\nTrokit për më shumë informacione"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefoni yt ishte tepër i nxehtë, prandaj u fik për t\'u ftohur. Telefoni tani punon normalisht.\n\nTelefoni mund të nxehet së tepërmi nëse ti:\n • Përdor aplikacione intensive për burimet (siç janë aplikacionet e lojërave, videove apo aplikacionet e navigimit)\n • Shkarkon ose ngarkon skedarë të mëdhenj\n • E përdor telefonin në temperatura të larta"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Shiko hapat për kujdesin"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefoni po bëhet i ngrohtë"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Disa veçori janë të kufizuara kur telefoni është duke u ftohur.\nTrokit për më shumë informacione"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefoni yt do të përpiqet automatikisht që të ftohet. Mund ta përdorësh përsëri telefonin, por ai mund të punojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të punojë si normalisht."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Shiko hapat për kujdesin"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Shkëpute pajisjen"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Pajisja jote po nxehet pranë portës së karikimit. Nëse është lidhur me një karikues ose një aksesor USB, shkëpute dhe trego kujdes pasi kablloja mund të jetë e nxehtë po ashtu."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index eb69224..6227d5d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Мени дугмета за укључивање"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Закључан екран"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон се искључио због топлоте"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефон сада нормално ради.\nДодирните за више информација"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефон је био преврућ, па се искључио да се охлади. Сада ради нормално.\n\nТелефон може превише да се угреје ако:\n • Користите апликације које захтевају пуно ресурса (нпр. видео игре, видео или апликације за навигацију)\n • Преузимате/отпремате велике датотеке\n • Користите телефон на високој температури"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Погледајте упозорења"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Телефон се загрејао"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Неке функције су ограничене док се телефон не охлади.\nДодирните за више информација"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон ће аутоматски покушати да се охлади. И даље ћете моћи да користите телефон, али ће спорије реаговати.\n\nКада се телефон охлади, нормално ће радити."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Погледајте упозорења"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Искључите уређај"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Уређај се загрева у близини порта за пуњење. Ако је повезан са пуњачем или USB опремом, искључите је и будите пажљиви јер и кабл може да буде врућ."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 7e2e006..7cf096f4 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Aktivera USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Läs mer"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skärmbild"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock har inaktiverats"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Håll olåst har inaktiverats"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmbilden sparas ..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Sparar skärmbild i jobbprofilen …"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Startmeny"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Låsskärm"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Mobilen stängdes av pga. värme"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonen fungerar nu som vanligt.\nTryck för mer information"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Mobilen var för varm och stängdes av för att kylas ned. Den fungerar nu som vanligt.\n\nMobilen kan bli för varm om du\n • använder resurskrävande appar (till exempel spel-, video- eller navigeringsappar)\n • laddar ned eller laddar upp stora filer\n • använder mobilen vid höga temperaturer."</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Visa alla skötselråd"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Mobilen börjar bli varm"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Vissa funktioner är begränsade medan telefonen svalnar.\nTryck för mer information"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Mobilen försöker svalna automatiskt. Du kan fortfarande använda mobilen, men den kan vara långsammare än vanligt.\n\nMobilen fungerar som vanligt när den har svalnat."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Visa alla skötselråd"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Koppla ur enheten"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Enheten börjar bli varm vid laddningsporten. Om den är ansluten till en laddare eller ett USB-tillbehör kopplar du ur den. Var försiktigt eftersom kabeln också kan vara varm."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 676edb7..892d369 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Washa kipengele cha USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Pata maelezo zaidi"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Picha ya skrini"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Kipengele cha Kuongeza muda wa Kutofunga Skrini kimezimwa"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Kiongeza Muda wa Kutofunga Skrini kimezimwa"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Inahifadhi picha ya skrini kwenye wasifu wa kazini…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Menyu ya kuzima/kuwasha"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Skrini iliyofungwa"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Simu ilizima kutokana na joto"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Simu yako sasa inafanya kazi ipasavyo.\nGusa ili upate maelezo zaidi"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Simu yako ilikuwa moto sana, kwa hivyo ilijizima ili ipoe. Simu yako sasa inafanya kazi ipasavyo.\n\nSimu yako inaweza kuwa moto sana ikiwa:\n • Unatumia programu zinazotumia vipengee vingi (kama vile michezo ya video, video au programu za uelekezaji)\n • Unapakua au upakie faili kubwa\n • Unatumia simu yako katika maeneo yenye halijoto ya juu"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Angalia hatua za utunzaji"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Joto la simu linaongezeka"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Baadhi ya vipengele havitatumika kwenye simu wakati inapoa.\nGusa ili upate maelezo zaidi"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Simu yako itajaribu kupoa kiotomatiki. Bado unaweza kutumia simu yako, lakini huenda ikafanya kazi polepole. \n\nPindi simu yako itakapopoa, itaendelea kufanya kazi kama kawaida."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Angalia hatua za utunzaji"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Chomoa kifaa chako"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Kifaa chako kinapata joto karibu na mlango wa kuchaji. Ikiwa kimeunganishwa kwenye chaja au kifuasi cha USB, kichomoe na uwe makini kwani kebo inaweza kuwa imepata joto."</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 9a2db6bfd..2b1d9d6 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -53,6 +53,9 @@
<dimen name="navigation_key_padding">25dp</dimen>
+ <!-- width of ImmersiveModeConfirmation (-1 for match_parent) -->
+ <dimen name="immersive_mode_cling_width">380dp</dimen>
+
<!-- Keyboard shortcuts helper -->
<dimen name="ksh_layout_width">488dp</dimen>
@@ -74,6 +77,9 @@
<dimen name="large_dialog_width">472dp</dimen>
<dimen name="large_screen_shade_header_height">42dp</dimen>
+ <!-- start padding is smaller to account for status icon margins coming from drawable itself -->
+ <dimen name="shade_header_system_icons_padding_start">11dp</dimen>
+ <dimen name="shade_header_system_icons_padding_end">12dp</dimen>
<!-- Lockscreen shade transition values -->
<dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index d053a7a..de913ac 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -20,13 +20,16 @@
<dimen name="status_bar_icons_padding_start">10dp</dimen>
<!-- gap on either side of status bar notification icons -->
- <dimen name="status_bar_icon_horizontal_margin">1dp</dimen>
+ <dimen name="status_bar_icon_horizontal_margin">1sp</dimen>
<dimen name="controls_header_horizontal_padding">28dp</dimen>
<dimen name="controls_content_margin_horizontal">40dp</dimen>
<dimen name="large_screen_shade_header_height">56dp</dimen>
+ <!-- it's a bit smaller on 720dp to account for status_bar_icon_horizontal_margin -->
+ <dimen name="shade_header_system_icons_padding_start">10dp</dimen>
+
<!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
<dimen name="biometric_auth_pattern_view_size">348dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 390bd47..3378e13 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USBயை இயக்கு"</string>
<string name="learn_more" msgid="4690632085667273811">"மேலும் அறிக"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ஸ்கிரீன்ஷாட்"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"நீண்டநேர அன்லாக் அம்சம் முடக்கப்பட்டது"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"அன்லாக் நீட்டிப்பு அம்சம் முடக்கப்பட்டது"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"பணிக் கணக்கில் ஸ்கிரீன்ஷாட் சேமிக்கப்படுகிறது…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"பவர் மெனு"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"லாக் ஸ்கிரீன்"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"வெப்பத்தினால் ஃபோன் ஆஃப் செய்யப்பட்டது"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"இப்போது உங்கள் மொபைல் இயல்புநிலையில் இயங்குகிறது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"உங்கள் ஃபோன் அதிகமாகச் சூடானதால், அதன் சூட்டைக் குறைக்க, ஆஃப் செய்யப்பட்டது. இப்போது உங்கள் ஃபோன் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருவனவற்றைச் செய்தால், ஃபோன் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (எ.கா: கேமிங், வீடியோ (அ) வழிகாட்டுதல் ஆப்ஸ்) பயன்படுத்துவது\n • பெரிய ஃபைல்களைப் பதிவிறக்குவது/பதிவேற்றுவது\n • அதிக வெப்பநிலையில் ஃபோனைப் பயன்படுத்துவது"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"மொபைல் சூடாகிறது"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"மொபைலின் வெப்ப அளவு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"உங்கள் மொபைலின் வெப்ப அளவு தானாகவே குறையும். தொடர்ந்து நீங்கள் மொபைலைப் பயன்படுத்தலாம், ஆனால் அதன் வேகம் குறைவாக இருக்கக்கூடும்.\n\nமொபைலின் வெப்ப அளவு குறைந்தவுடன், அது இயல்பு நிலையில் இயங்கும்."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"சாதன இணைப்பைத் துண்டித்தல்"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"சார்ஜிங் போர்ட்டிற்கு அருகே உங்கள் சாதனம் சூடாகிறது. சார்ஜருடனோ USB உபகரணத்துடனோ சாதனம் இணைக்கப்பட்டிருந்தால் அதன் இணைப்பைத் துண்டிக்கவும். கேபிளும் சூடாக இருக்கக்கூடும் என்பதால் கவனத்துடன் கையாளவும்."</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a6cbf3d..9e50548 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USBని ప్రారంభించండి"</string>
<string name="learn_more" msgid="4690632085667273811">"మరింత తెలుసుకోండి"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్షాట్"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"అన్లాక్ను పొడిగించడం డిజేబుల్ చేయబడింది"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ఎక్స్టెండ్ అన్లాక్ డిజేబుల్ చేయబడింది"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్ను పంపారు"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"స్క్రీన్షాట్ను వర్క్ ప్రొఫైల్కు సేవ్ చేస్తోంది…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"పవర్ మెనూ"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"లాక్ స్క్రీన్"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"వేడెక్కినందుకు ఫోన్ ఆఫ్ చేయబడింది"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తోంది.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n • వనరు-ఆధారిత యాప్లు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి యాప్లు) ఉపయోగించడం\n • పెద్ద ఫైళ్లను డౌన్లోడ్ లేదా అప్లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ ఫోన్ని ఉపయోగించడం"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"ఫోన్ వేడెక్కుతోంది"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ఫోన్ను చల్లబరిచే క్రమంలో కొన్ని ఫీచర్లు పరిమితం చేయబడ్డాయి.\nమరింత సమాచారం కోసం ట్యాప్ చేయండి"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ ఆటోమేటిక్గా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"మీ పరికరాన్ని అన్ప్లగ్ చేయండి"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"ఛార్జింగ్ పోర్ట్ దగ్గర ఉంచినప్పుడు మీ పరికరం వేడెక్కుతోంది. ఇది ఛార్జర్ లేదా USB యాక్సెసరీకి కనెక్ట్ చేసి ఉంటే, దాన్ని అన్ప్లగ్ చేసి, కేబుల్ వేడెక్కే అవకాశం కూడా ఉన్నందున జాగ్రత్త వహించండి."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 307d113..554324a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"เปิดใช้ USB"</string>
<string name="learn_more" msgid="4690632085667273811">"ดูข้อมูลเพิ่มเติม"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ภาพหน้าจอ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ปิดใช้ฟีเจอร์ขยายเวลาปลดล็อกอยู่"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"ปิดใช้ฟีเจอร์ปลดล็อกต่อเนื่องอยู่"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"กำลังบันทึกภาพหน้าจอไปยังโปรไฟล์งาน…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"เมนูเปิด/ปิด"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"หน้าจอล็อก"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"โทรศัพท์ปิดไปเพราะร้อนมาก"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"ขณะนี้โทรศัพท์ทำงานเป็นปกติ\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"โทรศัพท์ร้อนเกินไปจึงปิดเครื่องเพื่อให้เย็นลง ขณะนี้โทรศัพท์ทำงานเป็นปกติ\n\nโทรศัพท์อาจร้อนเกินไปหากคุณ\n • ใช้แอปที่ใช้ทรัพยากรมาก (เช่น เกม วิดีโอ หรือแอปการนำทาง)\n • ดาวน์โหลดหรืออัปโหลดไฟล์ขนาดใหญ่\n • ใช้โทรศัพท์ในอุณหภูมิที่สูง"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ดูขั้นตอนในการดูแลรักษา"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"โทรศัพท์เริ่มเครื่องร้อน"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์เย็นลง\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"โทรศัพท์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้โทรศัพท์ได้ แต่โทรศัพท์อาจทำงานช้าลง\n\nโทรศัพท์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ดูขั้นตอนในการดูแลรักษา"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"ถอดปลั๊กอุปกรณ์"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"บริเวณพอร์ตชาร์จของอุปกรณ์เริ่มจะร้อนแล้ว หากมีที่ชาร์จหรืออุปกรณ์เสริม USB เสียบอยู่ ให้ถอดออกอย่างระมัดระวังเพราะสายเส้นนั้นก็อาจจะร้อนด้วยเช่นกัน"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3997539..2c632ec 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Power menu"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Na-off ang telepono dahil sa init"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Maayos na ngayong gumagana ang iyong telepono.\nMag-tap para sa higit pang impormasyon"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Napakainit ng telepono, kaya nag-off ito para lumamig. Maayos na itong gumagana.\n\nMaaaring lubos na uminit ang telepono kapag:\n • Gumamit ka ng resource-intensive na app (gaya ng app para sa gaming, video, o navigation)\n • Nag-download o nag-upload ka ng malaking file\n • Ginamit mo ito sa mainit na lugar"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Tingnan ang mga hakbang sa pangangalaga"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Umiinit ang telepono"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Limitado ang ilang feature habang nagku-cool down ang telepono.\nMag-tap para sa higit pang impormasyon"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Awtomatikong susubukan ng iyong telepono na mag-cool down. Magagamit mo pa rin ang iyong telepono, ngunit maaaring mas mabagal ang paggana nito.\n\nKapag nakapag-cool down na ang iyong telepono, gagana na ito nang normal."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Tingnan ang mga hakbang sa pangangalaga"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Bunutin sa saksakan ang device"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Umiinit ang iyong device malapit sa charging port. Kung nakakonekta ito sa charger o USB accessory, bunutin ito sa saksakan, at mag-ingat dahil posibleng mainit din ang cable."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6962aa4..8430771 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB\'yi etkinleştir"</string>
<string name="learn_more" msgid="4690632085667273811">"Daha fazla bilgi"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekran görüntüsü"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock devre dışı"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Artırılmış Kilit Açma devre dışı"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Ekran görüntüsü iş profiline kaydediliyor…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Güç menüsü"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Kilit ekranı"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon ısındığından kapatıldı"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonunuz şu anda normal bir şekilde çalışıyor.\nDaha fazla bilgi için dokunun"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonunuz çok ısındığından soğuması için kapatıldı ve şu anda normal bir şekilde çalışıyor.\n\nTelefon şu koşullarda çok ısınabilir:\n • Yoğun kaynak gerektiren uygulamalar (oyun, video veya gezinme uygulamaları gibi) kullanma\n • Büyük dosyalar indirme veya yükleme\n • Telefonu sıcak yerlerde kullanma"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bakımla ilgili adımlara bakın"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon ısınıyor"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir.\nDaha fazla bilgi için dokunun"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz otomatik olarak soğumaya çalışacak. Bu sırada telefonunuzu kullanmaya devam edebilirsiniz ancak uygulamalar daha yavaş çalışabilir.\n\nTelefonunuz soğuduktan sonra normal şekilde çalışacaktır."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bakımla ilgili adımlara bakın"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Cihazınızın fişini çekin"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Cihazınız, şarj yuvasının yakınındayken ısınıyor. Şarj cihazına veya USB aksesuarına bağlıysa cihazı çıkarın. Ayrıca, kablo sıcak olabileceği için dikkatli olun."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 93807d0..b3ee948 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Увімкнути USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Докладніше"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Знімок екрана"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock вимкнено"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Відкладене блокування вимкнено"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Зберігання знімка екрана в робочому профілі…"</string>
@@ -143,7 +143,7 @@
<string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Підтверджено"</string>
<string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Щоб завершити, натисніть \"Підтвердити\""</string>
<string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"Розблоковано (фейс-контроль)"</string>
- <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Розблоковано (фейсконтроль). Натисніть, щоб продовжити."</string>
+ <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"Розблоковано (фейс-контроль). Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Обличчя розпізнано. Натисніть, щоб продовжити."</string>
<string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Обличчя розпізнано. Натисніть значок розблокування."</string>
<string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Автентифіковано"</string>
@@ -185,7 +185,7 @@
<skip />
<string name="keyguard_face_failed" msgid="9044619102286917151">"Обличчя не розпізнано"</string>
<string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скористайтеся відбитком"</string>
- <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Фейсконтроль недоступний"</string>
+ <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Фейс-контроль недоступний"</string>
<string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth під’єднано."</string>
<string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
<string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
@@ -351,12 +351,12 @@
<string name="tap_again" msgid="1315420114387908655">"Натисніть знову"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"Проведіть пальцем угору, щоб відкрити"</string>
<string name="keyguard_unlock_press" msgid="9140109453735019209">"Щоб відкрити, натисніть значок розблокування."</string>
- <string name="keyguard_face_successful_unlock_swipe" msgid="6180997591385846073">"Розблоковано (фейсконтроль). Відкрити: проведіть угору."</string>
- <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Розблоковано (фейсконтроль). Натисніть значок розблокування."</string>
- <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Розблоковано (фейсконтроль). Натисніть, щоб відкрити."</string>
+ <string name="keyguard_face_successful_unlock_swipe" msgid="6180997591385846073">"Розблоковано (фейс-контроль). Відкрити: проведіть угору."</string>
+ <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Розблоковано (фейс-контроль). Натисніть значок розблокування."</string>
+ <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"Розблоковано (фейс-контроль). Натисніть, щоб відкрити."</string>
<string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Обличчя розпізнано. Натисніть, щоб відкрити."</string>
<string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Обличчя розпізнано. Натисніть значок розблокування."</string>
- <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"Розблоковано (фейсконтроль)"</string>
+ <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"Розблоковано (фейс-контроль)"</string>
<string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"Обличчя розпізнано"</string>
<string name="keyguard_retry" msgid="886802522584053523">"Проведіть пальцем угору, щоб повторити спробу"</string>
<string name="require_unlock_for_nfc" msgid="1305686454823018831">"Розблокуйте екран, щоб скористатись NFC"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Меню кнопки живлення"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокований екран"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон перегрівся й вимкнувся"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Зараз телефон працює як зазвичай.\nНатисніть, щоб дізнатися більше"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефон перегрівся, тому вимкнувся, щоб охолонути. Зараз він працює, як зазвичай.\n\nТелефон перегрівається, якщо ви:\n • використовуєте ресурсомісткі додатки (ігри, відео, навігація)\n • завантажуєте великі файли на телефон або з нього\n • використовуєте телефон за високої температури"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Переглянути запобіжні заходи"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Телефон нагрівається"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Під час охолодження деякі функції обмежуються.\nНатисніть, щоб дізнатися більше"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон охолоджуватиметься автоматично. Ви можете далі користуватися телефоном, але він може працювати повільніше.\n\nКоли телефон охолоне, він працюватиме належним чином."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Переглянути запобіжні заходи"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Від’єднайте пристрій"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Пристрій нагрівається біля зарядного порту. Якщо він під’єднаний до зарядного пристрою або USB-аксесуара, від’єднайте його, однак будьте обережні, оскільки кабель також може бути гарячий."</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ff4965f..3f47187 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB پورٹ فعال کریں"</string>
<string name="learn_more" msgid="4690632085667273811">"مزید جانیں"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"اسکرین شاٹ"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"اَن لاک کی توسیع کو غیر فعال کیا گیا"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"اَن لاک کا دورانیہ بڑھائیں کو غیر فعال کیا گیا"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"اسکرین شاٹ دفتری پروفائل میں محفوظ کیا جا رہا ہے…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"پاور مینیو"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"مقفل اسکرین"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"حرارت کی وجہ سے فون آف ہو گیا"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"آپ کا فون اب حسب معمول چل رہا ہے۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"آپ کا فون کافی گرم ہو گيا تھا، اس لئے سرد ہونے کیلئے یہ آف ہو گیا۔ اب آپ کا فون حسب معمول کام کر رہا ہے۔\n\nمندرجہ ذیل چیزیں کرنے پر آپ کا فون کافی گرم ہو سکتا ہے:\n • ماخذ کا زیادہ استعمال کرنے والی ایپس (جیسے کہ گیمنگ، ویڈیو، یا نیویگیشن ایپس) کا استعمال کرنا\n • بڑی فائلز ڈاؤن لوڈ یا اپ لوڈ کرنا\n • اعلی درجہ حرارت میں فون کا استعمال کرنا"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"فون گرم ہو رہا ہے"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"فون کے ٹھنڈے ہو جانے تک کچھ خصوصیات محدود ہیں۔\nمزید معلومات کیلئے تھپتھپائیں"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"آپ کا فون خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ ابھی بھی اپنا فون استعمال کر سکتے ہیں، مگر ہو سکتا ہے یہ سست چلے۔\n\nایک بار آپ کا فون ٹھنڈا ہوجائے تو یہ معمول کے مطابق چلے گا۔"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"اپنے آلہ کو ان پلگ کریں"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"آپ کا آلہ چارجنگ پورٹ کے قریب گرم ہو رہا ہے۔ اگر یہ چارجر یا USB لوازمات سے منسلک ہے تو اسے ان پلگ کریں اور خیال رکھیں کہ کیبل بھی گرم ہو سکتی ہے۔"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 538fe16d..499eb1b 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"USB xususiyatini yoqish"</string>
<string name="learn_more" msgid="4690632085667273811">"Batafsil"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skrinshot"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Kengaytirilgan ochish yoniq emas"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Extend Unlock yoniq emas"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"rasm yuborildi"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinshot saqlanmoqda…"</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Skrinshot ish profiliga saqlanmoqda…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Quvvat menyusi"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran qulfi"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Qizigani uchun o‘chirildi"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Endi telefoningiz normal holatda ishlayapti.\nBatafsil axborot uchun bosing"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon qizib ketganligi sababli sovitish uchun o‘chirib qo‘yilgan. Endi telefoningiz normal holatda ishlayapti.\n\nTelefon bu hollarda qizib ketishi mumkin:\n • Resurstalab ilovalar ishlatilganda (masalan, o‘yin, video yoki navigatsiya ilovalari)\n • Katta faylni yuklab olishda yoki yuklashda\n • Telefondan yuqori haroratda foydalanganda"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Batafsil axborot"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Telefon qizib ketdi"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon sovib qolganda ayrim funksiyalari ishlamasligi mumkin.\nBatafsil axborot uchun bosing"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon avtomatik ravishda o‘zini sovitadi. Telefoningizdan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nTelefon sovishi bilan normal holatda ishlashni boshlaydi."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Batafsil axborot"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Qurilmani uzing"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Qurilmangiz quvvatlash porti yaqinida qizib ketmoqda. Agar quvvatlagich yoki USB aksessuarga ulangan boʻlsa, kabel qizib ketmasidan uni darhol uzing."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4120e57e..1d96b1e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -69,7 +69,7 @@
<string name="usb_disable_contaminant_detection" msgid="3827082183595978641">"Bật USB"</string>
<string name="learn_more" msgid="4690632085667273811">"Tìm hiểu thêm"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Chụp ảnh màn hình"</string>
- <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Đã tắt tính năng Luôn mở khoá"</string>
+ <string name="global_action_smart_lock_disabled" msgid="6286551337177954859">"Đã tắt tính năng Kéo dài trạng thái mở khoá"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"đã gửi hình ảnh"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Đang lưu ảnh chụp màn hình..."</string>
<string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"Đang lưu ảnh chụp màn hình vào hồ sơ công việc…"</string>
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Trình đơn nguồn"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Màn hình khóa"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Điện thoại đã tắt do nhiệt"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Điện thoại của bạn đang chạy bình thường.\nHãy nhấn để biết thêm thông tin"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Do quá nóng nên điện thoại đã tắt để hạ nhiệt. Hiện điện thoại của bạn đang chạy bình thường.\n\nĐiện thoại có thể bị quá nóng nếu bạn:\n • Dùng các ứng dụng tốn nhiều tài nguyên (như ứng dụng trò chơi, video hoặc điều hướng)\n • Tải xuống hoặc tải lên tệp có dung lượng lớn\n • Dùng điện thoại ở nhiệt độ cao"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Xem các bước chăm sóc"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Điện thoại đang nóng lên"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần.\nHãy nhấn để biết thêm thông tin"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Điện thoại của bạn sẽ tự động nguội dần. Bạn vẫn có thể sử dụng điện thoại, nhưng điện thoại có thể chạy chậm hơn. \n\nSau khi đã nguội, điện thoại sẽ chạy bình thường."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Xem các bước chăm sóc"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Rút thiết bị ra"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Phần gần cổng sạc của thiết bị đang nóng lên. Nếu thiết bị kết nối với bộ sạc hoặc phụ kiện USB, hãy rút ra một cách thận trọng vì cáp có thể cũng đang nóng."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e167c61..0699551 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"电源菜单"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"锁定屏幕"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"手机因严重发热而自动关机"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"现在,您的手机已恢复正常运行。\n点按即可了解详情"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"由于发热严重,因此您的手机执行了自动关机以降温。现在,您的手机已恢复正常运行。\n\n以下情况可能会导致您的手机严重发热:\n • 使用占用大量资源的应用(例如游戏、视频或导航应用)\n • 下载或上传大型文件\n • 在高温环境下使用手机"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看处理步骤"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"手机温度上升中"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"手机降温时,部分功能的使用会受限制。\n点按即可了解详情"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"您的手机将自动尝试降温。您依然可以使用您的手机,但是手机运行速度可能会更慢。\n\n手机降温后,就会恢复正常的运行速度。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看处理步骤"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"拔出设备"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"设备的充电接口附近在发热。如果该设备已连接到充电器或 USB 配件,请立即拔掉,并注意充电线也可能会发热。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 4066a89..7160b56 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源選單"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"螢幕鎖定"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"手機因過熱而關上"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"你的手機現已正常運作。\n輕按即可瞭解詳情"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"你的手機之前因過熱而關上降溫。手機現已正常運作。\n\n以下情況可能會導致手機過熱:\n • 使用耗用大量資源的應用程式 (例如遊戲、影片或導航應用程式)\n • 下載或上載大型檔案\n • 在高溫環境下使用手機"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看保養步驟"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"手機溫度正在上升"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,部分功能會受限制。\n輕按即可瞭解詳情"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。你仍可以使用手機,但手機的運作速度可能較慢。\n\n手機降溫後便會恢復正常。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看保養步驟"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"拔除裝置"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"充電埠附近的裝置溫度正在上升。如裝置正連接充電器或 USB 配件,請拔除裝置並小心安全,因為電線的溫度可能也偏高。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 7abe1de..0deba33 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"電源鍵選單"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"鎖定畫面"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"手機先前過熱,因此關閉電源"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"手機現在已恢復正常運作。\n輕觸即可瞭解詳情"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"手機先前的溫度過高,因此關閉了電源以進行降溫。手機現在已恢復正常運作。\n\n以下情況可能會導致你的手機溫度過高:\n • 使用需要密集處理資料的應用程式 (例如遊戲、影片或導航應用程式)\n • 下載或上傳大型檔案\n • 在高溫環境下使用手機"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看處理步驟"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"手機變熱"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,某些功能會受限。\n輕觸即可瞭解詳情"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。你仍可繼續使用手機,但是手機的運作速度可能會較慢。\n\n手機降溫完畢後,就會恢復正常的運作速度。"</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看處理步驟"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"拔除裝置"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"裝置的充電埠附近越來越熱。如果裝置已連接充電器或 USB 配件,請立即拔除。此外,電線也可能會變熱,請特別留意。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e5b4c14..eb8ee45 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -759,13 +759,7 @@
<string name="accessibility_quick_settings_power_menu" msgid="6820426108301758412">"Imenyu yamandla"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Khiya isikrini"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Ifoni ivaliwe ngenxa yokushisa"</string>
- <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ifoni yakho manje isebenza ngokuvamile.\nThepha ukuze uthole ulwazi olungeziwe"</string>
- <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ifoni yakho ibishisa kakhulu, ngakho-ke yacisha ukuze iphole. Ifoni yakho manje isebenza ngokuvamile.\n\nIfoni yakho ingashisa kakhulu uma:\n • Usebenzisa izinhlelo zokusebenza ezinkulu (njegegeyimu, ividiyo, noma izinhlelo zokusebenza zokuzula)\n • Landa noma layisha amafayela amakhulu\n • Sebenzisa ifoni yakho kumathempelesha aphezulu"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bona izinyathelo zokunakekelwa"</string>
- <string name="high_temp_title" msgid="2218333576838496100">"Ifoni iyafudumala"</string>
- <string name="high_temp_notif_message" msgid="1277346543068257549">"Ezinye izici zikhawulelwe ngenkathi ifoni iphola.\nThepha mayelana nolwazi olwengeziwe"</string>
- <string name="high_temp_dialog_message" msgid="3793606072661253968">"Ifoni yakho izozama ngokuzenzakalela ukuphola. Ungasasebenzisa ifoni yakho, kodwa ingasebenza ngokungasheshi.\n\nUma ifoni yakho isipholile, izosebenza ngokuvamile."</string>
<string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bona izinyathelo zokunakekelwa"</string>
<string name="high_temp_alarm_title" msgid="8654754369605452169">"Khipha idivayisi yakho"</string>
<string name="high_temp_alarm_notify_message" msgid="3917622943609118956">"Idivayisi yakho iqala ukufudumala eduze kwembobo yokushaja. Uma ixhunywe kushaja noma insiza ye-USB, yikhiphe, futhi uqaphele njengoba ikhebuli ingase ifudumale."</string>
diff --git a/packages/SystemUI/res/values/bools.xml b/packages/SystemUI/res/values/bools.xml
index 04fc4b8..405a59f 100644
--- a/packages/SystemUI/res/values/bools.xml
+++ b/packages/SystemUI/res/values/bools.xml
@@ -30,4 +30,25 @@
<!-- Whether to enable transparent background for notification scrims -->
<bool name="notification_scrim_transparent">false</bool>
+
+ <!-- Control whether to force apps to give up control over the display of system bars at all
+ times regardless of System Ui Flags.
+ In the Automotive case, this is helpful if there's a requirement for an UI element to be on
+ screen at all times. Setting this to true also gives System UI the ability to override the
+ visibility controls for the system through the usage of the
+ "SYSTEM_BAR_VISIBILITY_OVERRIDE" setting.
+ Ex: Only setting the config to true will force show system bars for the entire system.
+ Ex: Setting the config to true and the "SYSTEM_BAR_VISIBILITY_OVERRIDE" setting to
+ "immersive.status=apps" will force show navigation bar for all apps and force hide status
+ bar for all apps. -->
+ <bool name="config_remoteInsetsControllerControlsSystemBars">false</bool>
+
+ <!-- Control whether the system bars can be requested when using a remote insets control target.
+ This allows for specifying whether or not system bars can be shown by the user (via swipe
+ or other means) when they are hidden by the logic defined by the remote insets controller.
+ This is useful for cases where the system provides alternative affordances for showing and
+ hiding the bars or for cases in which it's desired the bars not be shown for any reason.
+ This configuration will only apply when config_remoteInsetsControllerControlsSystemBars.
+ is set to true. -->
+ <bool name="config_remoteInsetsControllerSystemBarsCanBeShownByUserAction">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3bd7a06..47cd1e7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -121,24 +121,26 @@
<dimen name="navigation_edge_cancelled_arrow_height">0dp</dimen>
<dimen name="navigation_edge_cancelled_edge_corners">6dp</dimen>
- <!-- Height of notification icons in the status bar -->
+ <!-- New sp height of notification icons in the status bar -->
+ <dimen name="status_bar_icon_size_sp">@*android:dimen/status_bar_icon_size_sp</dimen>
+ <!-- Original dp height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
<!-- Default horizontal drawable padding for status bar icons. -->
- <dimen name="status_bar_horizontal_padding">2.5dp</dimen>
+ <dimen name="status_bar_horizontal_padding">2.5sp</dimen>
<!-- Height of the battery icon in the status bar. -->
- <dimen name="status_bar_battery_icon_height">13.0dp</dimen>
+ <dimen name="status_bar_battery_icon_height">13.0sp</dimen>
<!-- Width of the battery icon in the status bar. The battery drawable assumes a 12x20 canvas,
- so the width of the icon should be 13.0dp * (12.0 / 20.0) -->
- <dimen name="status_bar_battery_icon_width">7.8dp</dimen>
+ so the width of the icon should be 13.0sp * (12.0 / 20.0) -->
+ <dimen name="status_bar_battery_icon_width">7.8sp</dimen>
- <!-- The battery icon is 13dp tall, but the other system icons are 15dp tall (see
+ <!-- The battery icon is 13sp tall, but the other system icons are 15sp tall (see
@*android:dimen/status_bar_system_icon_size) with some top and bottom padding embedded in
the drawables themselves. So, the battery icon may need an extra 1dp of spacing so that its
bottom still aligns with the bottom of all the other system icons. See b/258672854. -->
- <dimen name="status_bar_battery_extra_vertical_spacing">1dp</dimen>
+ <dimen name="status_bar_battery_extra_vertical_spacing">1sp</dimen>
<!-- The font size for the clock in the status bar. -->
<dimen name="status_bar_clock_size">14sp</dimen>
@@ -153,19 +155,26 @@
<dimen name="status_bar_left_clock_starting_padding">0dp</dimen>
<!-- End padding for left-aligned status bar clock -->
- <dimen name="status_bar_left_clock_end_padding">2dp</dimen>
+ <dimen name="status_bar_left_clock_end_padding">2sp</dimen>
<!-- Spacing after the wifi signals that is present if there are any icons following it. -->
- <dimen name="status_bar_wifi_signal_spacer_width">2.5dp</dimen>
+ <dimen name="status_bar_wifi_signal_spacer_width">2.5sp</dimen>
+ <!-- Size of the view displaying the wifi inout icon in the status bar. -->
+ <dimen name="status_bar_wifi_inout_container_size">17sp</dimen>
<!-- Size of the view displaying the wifi signal icon in the status bar. -->
- <dimen name="status_bar_wifi_signal_size">@*android:dimen/status_bar_system_icon_size</dimen>
+ <dimen name="status_bar_wifi_signal_size">13sp</dimen>
+
+ <!-- Size of the view displaying the mobile inout icon in the status bar. -->
+ <dimen name="status_bar_mobile_inout_container_size">17sp</dimen>
+ <!-- Size of the view displaying the mobile signal icon in the status bar. -->
+ <dimen name="status_bar_mobile_signal_size">13sp</dimen>
<!-- Spacing before the airplane mode icon if there are any icons preceding it. -->
- <dimen name="status_bar_airplane_spacer_width">4dp</dimen>
+ <dimen name="status_bar_airplane_spacer_width">4sp</dimen>
<!-- Spacing between system icons. -->
- <dimen name="status_bar_system_icon_spacing">0dp</dimen>
+ <dimen name="status_bar_system_icon_spacing">0sp</dimen>
<!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
@@ -235,6 +244,9 @@
and the notification won't use this much, but is measured with wrap_content -->
<dimen name="notification_messaging_actions_min_height">196dp</dimen>
+ <!-- width of ImmersiveModeConfirmation (-1 for match_parent) -->
+ <dimen name="immersive_mode_cling_width">-1px</dimen>
+
<!-- a threshold in dp per second that is considered fast scrolling -->
<dimen name="scroll_fast_threshold">1500dp</dimen>
@@ -335,7 +347,7 @@
<dimen name="status_bar_icons_padding_top">8dp</dimen>
<!-- gap on either side of status bar notification icons -->
- <dimen name="status_bar_icon_horizontal_margin">0dp</dimen>
+ <dimen name="status_bar_icon_horizontal_margin">0sp</dimen>
<!-- the padding on the start of the statusbar -->
<dimen name="status_bar_padding_start">8dp</dimen>
@@ -347,10 +359,10 @@
<dimen name="status_bar_padding_top">0dp</dimen>
<!-- the radius of the overflow dot in the status bar -->
- <dimen name="overflow_dot_radius">2dp</dimen>
+ <dimen name="overflow_dot_radius">2sp</dimen>
<!-- the padding between dots in the icon overflow -->
- <dimen name="overflow_icon_dot_padding">3dp</dimen>
+ <dimen name="overflow_icon_dot_padding">3sp</dimen>
<!-- Dimensions related to screenshots -->
@@ -470,6 +482,10 @@
<dimen name="large_screen_shade_header_height">48dp</dimen>
<dimen name="large_screen_shade_header_min_height">@dimen/qs_header_row_min_height</dimen>
<dimen name="large_screen_shade_header_left_padding">@dimen/qs_horizontal_margin</dimen>
+ <dimen name="shade_header_system_icons_height">@dimen/large_screen_shade_header_min_height</dimen>
+ <dimen name="shade_header_system_icons_height_large_screen">32dp</dimen>
+ <dimen name="shade_header_system_icons_padding_start">0dp</dimen>
+ <dimen name="shade_header_system_icons_padding_end">0dp</dimen>
<!-- The top margin of the panel that holds the list of notifications.
On phones it's always 0dp but it's overridden in Car UI
@@ -731,8 +747,6 @@
<dimen name="keyguard_clock_switch_y_shift">14dp</dimen>
<!-- When large clock is showing, offset the smartspace by this amount -->
<dimen name="keyguard_smartspace_top_offset">12dp</dimen>
- <!-- With the large clock, move up slightly from the center -->
- <dimen name="keyguard_large_clock_top_margin">-60dp</dimen>
<dimen name="notification_scrim_corner_radius">32dp</dimen>
@@ -838,7 +852,7 @@
<!-- Padding between the mobile signal indicator and the start icon when the roaming icon
is displayed in the upper left corner. -->
- <dimen name="roaming_icon_start_padding">2dp</dimen>
+ <dimen name="roaming_icon_start_padding">2sp</dimen>
<!-- Extra padding between the mobile data type icon and the strength indicator when the data
type icon is wide for the tile in quick settings. -->
@@ -1064,7 +1078,7 @@
<!-- Margin between icons of Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_icon_margin">4dp</dimen>
<!-- Icon size of Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_icon_size">16dp</dimen>
+ <dimen name="ongoing_appops_chip_icon_size">16sp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
<dimen name="ongoing_appops_chip_bg_corner_radius">28dp</dimen>
<!-- One or two privacy items -->
@@ -1793,7 +1807,6 @@
<dimen name="dream_overlay_status_bar_ambient_text_shadow_dy">0.5dp</dimen>
<dimen name="dream_overlay_status_bar_ambient_text_shadow_radius">2dp</dimen>
<dimen name="dream_overlay_icon_inset_dimen">0dp</dimen>
- <dimen name="dream_overlay_status_bar_marginTop">22dp</dimen>
<!-- Default device corner radius, used for assist UI -->
<dimen name="config_rounded_mask_size">0px</dimen>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index 675ae32..c925b26 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -21,6 +21,8 @@
<integer name="magnification_default_scale">2</integer>
+ <integer name="dock_enter_exit_duration">250</integer>
+
<!-- The position of the volume dialog on the screen.
See com.android.systemui.volume.VolumeDialogImpl.
Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a36f318..81012a75 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -300,6 +300,13 @@
<!-- A toast message shown when the screen recording cannot be started due to a generic error [CHAR LIMIT=NONE] -->
<string name="screenrecord_start_error">Error starting screen recording</string>
+ <!-- Cling help message title when hiding the navigation bar entering immersive mode [CHAR LIMIT=none] -->
+ <string name="immersive_cling_title">Viewing full screen</string>
+ <!-- Cling help message description when hiding the navigation bar entering immersive mode [CHAR LIMIT=none] -->
+ <string name="immersive_cling_description">To exit, swipe down from the top.</string>
+ <!-- Cling help message confirmation button when hiding the navigation bar entering immersive mode [CHAR LIMIT=30] -->
+ <string name="immersive_cling_positive">Got it</string>
+
<!-- Content description of the back button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_back">Back</string>
<!-- Content description of the home button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index fd74c7e..6b85621 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -398,7 +398,8 @@
<item name="android:itemTextAppearance">@style/Control.MenuItem</item>
</style>
- <style name="Theme.SystemUI.QuickSettings.BrightnessDialog" parent="@android:style/Theme.DeviceDefault.Dialog">
+ <!-- Cannot double inherit. Use Theme.SystemUI.QuickSettings in code to match -->
+ <style name="BrightnessDialog" parent="@android:style/Theme.DeviceDefault.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
</style>
diff --git a/packages/SystemUI/res/xml/large_screen_shade_header.xml b/packages/SystemUI/res/xml/large_screen_shade_header.xml
index 39f4c81..cb2c3a1 100644
--- a/packages/SystemUI/res/xml/large_screen_shade_header.xml
+++ b/packages/SystemUI/res/xml/large_screen_shade_header.xml
@@ -56,7 +56,7 @@
<Constraint android:id="@+id/shade_header_system_icons">
<Layout
android:layout_width="wrap_content"
- android:layout_height="@dimen/large_screen_shade_header_min_height"
+ android:layout_height="@dimen/shade_header_system_icons_height_large_screen"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/privacy_container"
app:layout_constraintTop_toTopOf="parent"
diff --git a/packages/SystemUI/screenshot/Android.bp b/packages/SystemUI/screenshot/Android.bp
deleted file mode 100644
index f449398..0000000
--- a/packages/SystemUI/screenshot/Android.bp
+++ /dev/null
@@ -1,45 +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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
-}
-
-android_library {
- name: "SystemUIScreenshotLib",
- manifest: "AndroidManifest.xml",
-
- srcs: [
- "src/**/*.kt",
- ],
-
- resource_dirs: [
- "res",
- ],
-
- static_libs: [
- "SystemUI-core",
- "androidx.test.espresso.core",
- "androidx.appcompat_appcompat",
- "platform-screenshot-diff-core",
- "guava",
- ],
-
- kotlincflags: ["-Xjvm-default=all"],
-}
diff --git a/packages/SystemUI/screenshot/AndroidManifest.xml b/packages/SystemUI/screenshot/AndroidManifest.xml
deleted file mode 100644
index ba3dc8c..0000000
--- a/packages/SystemUI/screenshot/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.systemui.testing.screenshot">
- <application>
- <activity
- android:name="com.android.systemui.testing.screenshot.ScreenshotActivity"
- android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
- android:exported="true"
- android:theme="@style/Theme.SystemUI.Screenshot" />
- </application>
-</manifest>
diff --git a/packages/SystemUI/screenshot/res/values/themes.xml b/packages/SystemUI/screenshot/res/values/themes.xml
deleted file mode 100644
index a7f8a26..0000000
--- a/packages/SystemUI/screenshot/res/values/themes.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources>
- <style name="Theme.SystemUI.Screenshot" parent="Theme.SystemUI">
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
-
- <!-- We make the status and navigation bars transparent so that the screenshotted content is
- not clipped by the status bar height when drawn into the Bitmap (which is what happens
- given that we draw the view into the Bitmap using hardware acceleration). -->
- <item name="android:statusBarColor">@android:color/transparent</item>
- <item name="android:navigationBarColor">@android:color/transparent</item>
-
- <!-- Make sure that device specific cutouts don't impact the outcome of screenshot tests -->
- <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
- </style>
-</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/Bitmap.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/Bitmap.kt
deleted file mode 100644
index a4a70a4..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/Bitmap.kt
+++ /dev/null
@@ -1,66 +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.testing.screenshot
-
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.os.Build
-import android.view.View
-import platform.test.screenshot.matchers.MSSIMMatcher
-import platform.test.screenshot.matchers.PixelPerfectMatcher
-
-/** Draw this [View] into a [Bitmap]. */
-// TODO(b/195673633): Remove this once Compose screenshot tests use hardware rendering for their
-// tests.
-fun View.drawIntoBitmap(): Bitmap {
- val bitmap =
- Bitmap.createBitmap(
- measuredWidth,
- measuredHeight,
- Bitmap.Config.ARGB_8888,
- )
- val canvas = Canvas(bitmap)
- draw(canvas)
- return bitmap
-}
-
-/**
- * The [BitmapMatcher][platform.test.screenshot.matchers.BitmapMatcher] that should be used for
- * screenshot *unit* tests.
- */
-val UnitTestBitmapMatcher =
- if (Build.CPU_ABI == "x86_64") {
- // Different CPU architectures can sometimes end up rendering differently, so we can't do
- // pixel-perfect matching on different architectures using the same golden. Given that our
- // presubmits are run on cf_x86_64_phone, our goldens should be perfectly matched on the
- // x86_64 architecture and use the Structural Similarity Index on others.
- // TODO(b/237511747): Run our screenshot presubmit tests on arm64 instead so that we can
- // do pixel perfect matching both at presubmit time and at development time with actual
- // devices.
- PixelPerfectMatcher()
- } else {
- MSSIMMatcher()
- }
-
-/**
- * The [BitmapMatcher][platform.test.screenshot.matchers.BitmapMatcher] that should be used for
- * screenshot *unit* tests.
- *
- * We use the Structural Similarity Index for integration tests because they usually contain
- * additional information and noise that shouldn't break the test.
- */
-val IntegrationTestBitmapMatcher = MSSIMMatcher()
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
deleted file mode 100644
index e032bb9..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
+++ /dev/null
@@ -1,107 +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.testing.screenshot
-
-import android.app.Activity
-import android.graphics.Color
-import android.view.View
-import android.view.Window
-import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
-import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.WindowInsetsControllerCompat
-import androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
-import androidx.test.platform.app.InstrumentationRegistry
-import org.junit.rules.RuleChain
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-import platform.test.screenshot.*
-
-/**
- * A rule that allows to run a screenshot diff test on a view that is hosted in another activity.
- */
-class ExternalViewScreenshotTestRule(
- emulationSpec: DeviceEmulationSpec,
- assetPathRelativeToBuildRoot: String
-) : TestRule {
-
- private val colorsRule = MaterialYouColorsRule()
- private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
- private val screenshotRule =
- ScreenshotTestRule(
- SystemUIGoldenImagePathManager(
- getEmulatedDevicePathConfig(emulationSpec),
- assetPathRelativeToBuildRoot
- )
- )
- private val delegateRule =
- RuleChain.outerRule(colorsRule).around(deviceEmulationRule).around(screenshotRule)
- private val matcher = UnitTestBitmapMatcher
-
- override fun apply(base: Statement, description: Description): Statement {
- return delegateRule.apply(base, description)
- }
-
- /**
- * Compare the content of the [view] with the golden image identified by [goldenIdentifier] in
- * the context of [emulationSpec]. Window must be specified to capture views that render
- * hardware buffers.
- */
- fun screenshotTest(goldenIdentifier: String, view: View, window: Window? = null) {
- view.removeElevationRecursively()
-
- ScreenshotRuleAsserter.Builder(screenshotRule)
- .setScreenshotProvider { view.toBitmap(window) }
- .withMatcher(matcher)
- .build()
- .assertGoldenImage(goldenIdentifier)
- }
-
- /**
- * Compare the content of the [activity] with the golden image identified by [goldenIdentifier]
- * in the context of [emulationSpec].
- */
- fun activityScreenshotTest(
- goldenIdentifier: String,
- activity: Activity,
- ) {
- val rootView = activity.window.decorView
-
- // Hide system bars, remove insets, focus and make sure device-specific cutouts
- // don't affect screenshots
- InstrumentationRegistry.getInstrumentation().runOnMainSync {
- val window = activity.window
- window.setDecorFitsSystemWindows(false)
- WindowInsetsControllerCompat(window, rootView).apply {
- hide(WindowInsetsCompat.Type.systemBars())
- systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
- }
-
- window.statusBarColor = Color.TRANSPARENT
- window.navigationBarColor = Color.TRANSPARENT
- window.attributes =
- window.attributes.apply {
- layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
- }
-
- rootView.removeInsetsRecursively()
- activity.currentFocus?.clearFocus()
- }
-
- screenshotTest(goldenIdentifier, rootView, activity.window)
- }
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
deleted file mode 100644
index 72d8c5a..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
+++ /dev/null
@@ -1,44 +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.testing.screenshot
-
-import androidx.test.platform.app.InstrumentationRegistry
-import platform.test.screenshot.GoldenImagePathManager
-import platform.test.screenshot.PathConfig
-
-/** A [GoldenImagePathManager] that should be used for all SystemUI screenshot tests. */
-class SystemUIGoldenImagePathManager(
- pathConfig: PathConfig,
- assetsPathRelativeToBuildRoot: String
-) :
- GoldenImagePathManager(
- appContext = InstrumentationRegistry.getInstrumentation().context,
- assetsPathRelativeToBuildRoot = assetsPathRelativeToBuildRoot,
- deviceLocalPath =
- InstrumentationRegistry.getInstrumentation()
- .targetContext
- .filesDir
- .absolutePath
- .toString() + "/sysui_screenshots",
- pathConfig = pathConfig,
- ) {
- override fun toString(): String {
- // This string is appended to all actual/expected screenshots on the device, so make sure
- // it is a static value.
- return "SystemUIGoldenImagePathManager"
- }
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt
deleted file mode 100644
index 98e9aaf..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt
+++ /dev/null
@@ -1,60 +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.testing.screenshot
-
-import android.app.Activity
-import android.content.Intent
-import androidx.core.app.AppComponentFactory
-
-class TestAppComponentFactory : AppComponentFactory() {
-
- init {
- instance = this
- }
-
- private val overrides: MutableMap<String, () -> Activity> = hashMapOf()
-
- fun clearOverrides() {
- overrides.clear()
- }
-
- fun <T : Activity> registerActivityOverride(activity: Class<T>, provider: () -> T) {
- overrides[activity.name] = provider
- }
-
- override fun instantiateActivityCompat(
- cl: ClassLoader,
- className: String,
- intent: Intent?
- ): Activity {
- return overrides
- .getOrDefault(className) { super.instantiateActivityCompat(cl, className, intent) }
- .invoke()
- }
-
- companion object {
-
- private var instance: TestAppComponentFactory? = null
-
- fun getInstance(): TestAppComponentFactory =
- instance
- ?: error(
- "TestAppComponentFactory is not initialized, " +
- "did you specify it in the manifest?"
- )
- }
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
deleted file mode 100644
index b84d26a..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
+++ /dev/null
@@ -1,42 +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.testing.screenshot
-
-import android.view.View
-import android.view.ViewGroup
-import com.android.systemui.util.children
-import android.view.WindowInsets
-
-/**
- * Elevation/shadows is not deterministic when doing hardware rendering, this exentsion allows to
- * disable it for any view in the hierarchy.
- */
-fun View.removeElevationRecursively() {
- this.elevation = 0f
- (this as? ViewGroup)?.children?.forEach(View::removeElevationRecursively)
-}
-
-/**
- * Different devices could have different insets (e.g. different height of the navigation bar or
- * taskbar). This method dispatches empty insets to the whole view hierarchy and removes
- * the original listener, so the views won't receive real insets.
- */
-fun View.removeInsetsRecursively() {
- this.dispatchApplyWindowInsets(WindowInsets.CONSUMED)
- this.setOnApplyWindowInsetsListener(null)
- (this as? ViewGroup)?.children?.forEach(View::removeInsetsRecursively)
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
deleted file mode 100644
index dedf0a7..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
+++ /dev/null
@@ -1,233 +0,0 @@
-package com.android.systemui.testing.screenshot
-
-import android.annotation.WorkerThread
-import android.app.Activity
-import android.content.Context
-import android.content.ContextWrapper
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.graphics.HardwareRenderer
-import android.graphics.Rect
-import android.os.Build
-import android.os.Handler
-import android.os.Looper
-import android.util.Log
-import android.view.PixelCopy
-import android.view.SurfaceView
-import android.view.View
-import android.view.ViewTreeObserver
-import android.view.Window
-import androidx.annotation.RequiresApi
-import androidx.concurrent.futures.ResolvableFuture
-import androidx.test.annotation.ExperimentalTestApi
-import androidx.test.core.internal.os.HandlerExecutor
-import androidx.test.espresso.Espresso
-import androidx.test.platform.graphics.HardwareRendererCompat
-import com.google.common.util.concurrent.FutureCallback
-import com.google.common.util.concurrent.Futures
-import com.google.common.util.concurrent.ListenableFuture
-import kotlin.coroutines.suspendCoroutine
-import kotlinx.coroutines.runBlocking
-
-/*
- * This file was forked from androidx/test/core/view/ViewCapture.kt to add [Window] parameter to
- * [View.captureToBitmap].
- * TODO(b/195673633): Remove this fork and use the AndroidX version instead.
- */
-
-/**
- * Asynchronously captures an image of the underlying view into a [Bitmap].
- *
- * For devices below [Build.VERSION_CODES#O] (or if the view's window cannot be determined), the
- * image is obtained using [View#draw]. Otherwise, [PixelCopy] is used.
- *
- * This method will also enable [HardwareRendererCompat#setDrawingEnabled(boolean)] if required.
- *
- * This API is primarily intended for use in lower layer libraries or frameworks. For test authors,
- * its recommended to use espresso or compose's captureToImage.
- *
- * This API is currently experimental and subject to change or removal.
- */
-@ExperimentalTestApi
-@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
-fun View.captureToBitmap(window: Window? = null): ListenableFuture<Bitmap> {
- val bitmapFuture: ResolvableFuture<Bitmap> = ResolvableFuture.create()
- val mainExecutor = HandlerExecutor(Handler(Looper.getMainLooper()))
- val isRobolectric = if (Build.FINGERPRINT.contains("robolectric")) true else false
-
- // disable drawing again if necessary once work is complete
- if (!HardwareRendererCompat.isDrawingEnabled()) {
- HardwareRendererCompat.setDrawingEnabled(true)
- bitmapFuture.addListener({ HardwareRendererCompat.setDrawingEnabled(false) }, mainExecutor)
- }
-
- mainExecutor.execute {
- if (isRobolectric) {
- generateBitmap(bitmapFuture)
- } else {
- val forceRedrawFuture = forceRedraw()
- forceRedrawFuture.addListener({ generateBitmap(bitmapFuture, window) }, mainExecutor)
- }
- }
-
- return bitmapFuture
-}
-
-/**
- * Synchronously captures an image of the view into a [Bitmap]. Synchronous equivalent of
- * [captureToBitmap].
- */
-@WorkerThread
-@ExperimentalTestApi
-@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
-fun View.toBitmap(window: Window? = null): Bitmap {
- if (Looper.getMainLooper() == Looper.myLooper()) {
- error("toBitmap() can't be called from the main thread")
- }
-
- if (!HardwareRenderer.isDrawingEnabled()) {
- error("Hardware rendering is not enabled")
- }
-
- // Make sure we are idle.
- Espresso.onIdle()
-
- val mainExecutor = context.mainExecutor
- return runBlocking {
- suspendCoroutine { continuation ->
- Futures.addCallback(
- captureToBitmap(window),
- object : FutureCallback<Bitmap> {
- override fun onSuccess(result: Bitmap?) {
- continuation.resumeWith(Result.success(result!!))
- }
-
- override fun onFailure(t: Throwable) {
- continuation.resumeWith(Result.failure(t))
- }
- },
- // We know that we are not on the main thread, so we can block the current
- // thread and wait for the result in the main thread.
- mainExecutor,
- )
- }
- }
-}
-
-/**
- * Trigger a redraw of the given view.
- *
- * Should only be called on UI thread.
- *
- * @return a [ListenableFuture] that will be complete once ui drawing is complete
- */
-// NoClassDefFoundError occurs on API 15
-@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
-// @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-@ExperimentalTestApi
-fun View.forceRedraw(): ListenableFuture<Void> {
- val future: ResolvableFuture<Void> = ResolvableFuture.create()
-
- if (Build.VERSION.SDK_INT >= 29 && isHardwareAccelerated) {
- viewTreeObserver.registerFrameCommitCallback() { future.set(null) }
- } else {
- viewTreeObserver.addOnDrawListener(
- object : ViewTreeObserver.OnDrawListener {
- var handled = false
- override fun onDraw() {
- if (!handled) {
- handled = true
- future.set(null)
- // cannot remove on draw listener inside of onDraw
- Handler(Looper.getMainLooper()).post {
- viewTreeObserver.removeOnDrawListener(this)
- }
- }
- }
- }
- )
- }
- invalidate()
- return future
-}
-
-private fun View.generateBitmap(
- bitmapFuture: ResolvableFuture<Bitmap>,
- window: Window? = null,
-) {
- if (bitmapFuture.isCancelled) {
- return
- }
- val destBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
- when {
- Build.VERSION.SDK_INT < 26 -> generateBitmapFromDraw(destBitmap, bitmapFuture)
- this is SurfaceView -> generateBitmapFromSurfaceViewPixelCopy(destBitmap, bitmapFuture)
- else -> {
- val window = window ?: getActivity()?.window
- if (window != null) {
- generateBitmapFromPixelCopy(window, destBitmap, bitmapFuture)
- } else {
- Log.i(
- "View.captureToImage",
- "Could not find window for view. Falling back to View#draw instead of PixelCopy"
- )
- generateBitmapFromDraw(destBitmap, bitmapFuture)
- }
- }
- }
-}
-
-@SuppressWarnings("NewApi")
-private fun SurfaceView.generateBitmapFromSurfaceViewPixelCopy(
- destBitmap: Bitmap,
- bitmapFuture: ResolvableFuture<Bitmap>
-) {
- val onCopyFinished =
- PixelCopy.OnPixelCopyFinishedListener { result ->
- if (result == PixelCopy.SUCCESS) {
- bitmapFuture.set(destBitmap)
- } else {
- bitmapFuture.setException(
- RuntimeException(String.format("PixelCopy failed: %d", result))
- )
- }
- }
- PixelCopy.request(this, null, destBitmap, onCopyFinished, handler)
-}
-
-internal fun View.generateBitmapFromDraw(
- destBitmap: Bitmap,
- bitmapFuture: ResolvableFuture<Bitmap>
-) {
- destBitmap.density = resources.displayMetrics.densityDpi
- computeScroll()
- val canvas = Canvas(destBitmap)
- canvas.translate((-scrollX).toFloat(), (-scrollY).toFloat())
- draw(canvas)
- bitmapFuture.set(destBitmap)
-}
-
-private fun View.getActivity(): Activity? {
- fun Context.getActivity(): Activity? {
- return when (this) {
- is Activity -> this
- is ContextWrapper -> this.baseContext.getActivity()
- else -> null
- }
- }
- return context.getActivity()
-}
-
-private fun View.generateBitmapFromPixelCopy(
- window: Window,
- destBitmap: Bitmap,
- bitmapFuture: ResolvableFuture<Bitmap>
-) {
- val locationInWindow = intArrayOf(0, 0)
- getLocationInWindow(locationInWindow)
- val x = locationInWindow[0]
- val y = locationInWindow[1]
- val boundsInWindow = Rect(x, y, x + width, y + height)
-
- return window.generateBitmapFromPixelCopy(boundsInWindow, destBitmap, bitmapFuture)
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
deleted file mode 100644
index 070a451..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ /dev/null
@@ -1,188 +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.testing.screenshot
-
-import android.app.Activity
-import android.app.Dialog
-import android.graphics.Bitmap
-import android.os.Build
-import android.view.View
-import android.view.ViewGroup
-import android.view.ViewGroup.LayoutParams
-import android.view.ViewGroup.LayoutParams.MATCH_PARENT
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
-import androidx.activity.ComponentActivity
-import androidx.test.ext.junit.rules.ActivityScenarioRule
-import java.util.concurrent.TimeUnit
-import org.junit.Assert.assertEquals
-import org.junit.rules.RuleChain
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-import platform.test.screenshot.DeviceEmulationRule
-import platform.test.screenshot.DeviceEmulationSpec
-import platform.test.screenshot.MaterialYouColorsRule
-import platform.test.screenshot.ScreenshotTestRule
-import platform.test.screenshot.getEmulatedDevicePathConfig
-import platform.test.screenshot.matchers.BitmapMatcher
-
-/** A rule for View screenshot diff unit tests. */
-open class ViewScreenshotTestRule(
- emulationSpec: DeviceEmulationSpec,
- private val matcher: BitmapMatcher = UnitTestBitmapMatcher,
- assetsPathRelativeToBuildRoot: String
-) : TestRule {
- private val colorsRule = MaterialYouColorsRule()
- private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
- protected val screenshotRule =
- ScreenshotTestRule(
- SystemUIGoldenImagePathManager(
- getEmulatedDevicePathConfig(emulationSpec),
- assetsPathRelativeToBuildRoot
- )
- )
- private val activityRule = ActivityScenarioRule(ScreenshotActivity::class.java)
- private val roboRule =
- RuleChain.outerRule(deviceEmulationRule).around(screenshotRule).around(activityRule)
- private val delegateRule = RuleChain.outerRule(colorsRule).around(roboRule)
- private val isRobolectric = if (Build.FINGERPRINT.contains("robolectric")) true else false
-
- override fun apply(base: Statement, description: Description): Statement {
- if (isRobolectric) {
- // In robolectric mode, we enable NATIVE graphics and unpack font and icu files.
- // We need to use reflection, as this library is only needed and therefore
- // only available in deviceless mode.
- val nativeLoaderClassName = "org.robolectric.nativeruntime.DefaultNativeRuntimeLoader"
- val defaultNativeRuntimeLoader = Class.forName(nativeLoaderClassName)
- System.setProperty("robolectric.graphicsMode", "NATIVE")
- defaultNativeRuntimeLoader.getMethod("injectAndLoad").invoke(null)
- }
- val ruleToApply = if (isRobolectric) roboRule else delegateRule
- return ruleToApply.apply(base, description)
- }
-
- protected fun takeScreenshot(
- mode: Mode = Mode.WrapContent,
- viewProvider: (ComponentActivity) -> View,
- beforeScreenshot: (ComponentActivity) -> Unit = {}
- ): Bitmap {
- activityRule.scenario.onActivity { activity ->
- // Make sure that the activity draws full screen and fits the whole display instead of
- // the system bars.
- val window = activity.window
- window.setDecorFitsSystemWindows(false)
-
- // Set the content.
- activity.setContentView(viewProvider(activity), mode.layoutParams)
-
- // Elevation/shadows is not deterministic when doing hardware rendering, so we disable
- // it for any view in the hierarchy.
- window.decorView.removeElevationRecursively()
-
- activity.currentFocus?.clearFocus()
- }
-
- // We call onActivity again because it will make sure that our Activity is done measuring,
- // laying out and drawing its content (that we set in the previous onActivity lambda).
- var contentView: View? = null
- activityRule.scenario.onActivity { activity ->
- // Check that the content is what we expected.
- val content = activity.requireViewById<ViewGroup>(android.R.id.content)
- assertEquals(1, content.childCount)
- contentView = content.getChildAt(0)
- beforeScreenshot(activity)
- }
-
- return if (isRobolectric) {
- contentView?.captureToBitmap()?.get(10, TimeUnit.SECONDS)
- ?: error("timeout while trying to capture view to bitmap")
- } else {
- contentView?.toBitmap() ?: error("contentView is null")
- }
- }
-
- /**
- * Compare the content of the view provided by [viewProvider] with the golden image identified
- * by [goldenIdentifier] in the context of [emulationSpec].
- */
- fun screenshotTest(
- goldenIdentifier: String,
- mode: Mode = Mode.WrapContent,
- beforeScreenshot: (ComponentActivity) -> Unit = {},
- viewProvider: (ComponentActivity) -> View
- ) {
- val bitmap = takeScreenshot(mode, viewProvider, beforeScreenshot)
- screenshotRule.assertBitmapAgainstGolden(
- bitmap,
- goldenIdentifier,
- matcher,
- )
- }
-
- /**
- * Compare the content of the dialog provided by [dialogProvider] with the golden image
- * identified by [goldenIdentifier] in the context of [emulationSpec].
- */
- fun dialogScreenshotTest(
- goldenIdentifier: String,
- dialogProvider: (Activity) -> Dialog,
- ) {
- var dialog: Dialog? = null
- activityRule.scenario.onActivity { activity ->
- dialog =
- dialogProvider(activity).apply {
- // Make sure that the dialog draws full screen and fits the whole display
- // instead of the system bars.
- window.setDecorFitsSystemWindows(false)
-
- // Disable enter/exit animations.
- create()
- window.setWindowAnimations(0)
-
- // Elevation/shadows is not deterministic when doing hardware rendering, so we
- // disable it for any view in the hierarchy.
- window.decorView.removeElevationRecursively()
-
- // Show the dialog.
- show()
- }
- }
-
- try {
- val bitmap = dialog?.toBitmap() ?: error("dialog is null")
- screenshotRule.assertBitmapAgainstGolden(
- bitmap,
- goldenIdentifier,
- matcher,
- )
- } finally {
- dialog?.dismiss()
- }
- }
-
- private fun Dialog.toBitmap(): Bitmap {
- val window = window
- return window.decorView.toBitmap(window)
- }
-
- enum class Mode(val layoutParams: LayoutParams) {
- WrapContent(LayoutParams(WRAP_CONTENT, WRAP_CONTENT)),
- MatchSize(LayoutParams(MATCH_PARENT, MATCH_PARENT)),
- MatchWidth(LayoutParams(MATCH_PARENT, WRAP_CONTENT)),
- MatchHeight(LayoutParams(WRAP_CONTENT, MATCH_PARENT)),
- }
-}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/WindowCapture.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/WindowCapture.kt
deleted file mode 100644
index d34f46b..0000000
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/WindowCapture.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.android.systemui.testing.screenshot
-
-import android.graphics.Bitmap
-import android.graphics.Rect
-import android.os.Handler
-import android.os.Looper
-import android.view.PixelCopy
-import android.view.Window
-import androidx.concurrent.futures.ResolvableFuture
-
-/*
- * This file was forked from androidx/test/core/view/WindowCapture.kt.
- * TODO(b/195673633): Remove this fork and use the AndroidX version instead.
- */
-fun Window.generateBitmapFromPixelCopy(
- boundsInWindow: Rect? = null,
- destBitmap: Bitmap,
- bitmapFuture: ResolvableFuture<Bitmap>
-) {
- val onCopyFinished =
- PixelCopy.OnPixelCopyFinishedListener { result ->
- if (result == PixelCopy.SUCCESS) {
- bitmapFuture.set(destBitmap)
- } else {
- bitmapFuture.setException(
- RuntimeException(String.format("PixelCopy failed: %d", result))
- )
- }
- }
- PixelCopy.request(
- this,
- boundsInWindow,
- destBitmap,
- onCopyFinished,
- Handler(Looper.getMainLooper())
- )
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
index e02e592..96a974d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/util/TraceUtils.kt
@@ -67,7 +67,7 @@
* under a single track.
*/
inline fun <T> traceAsync(method: String, block: () -> T): T =
- traceAsync(method, "AsyncTraces", block)
+ traceAsync("AsyncTraces", method, block)
/**
* Creates an async slice in a track with [trackName] while [block] runs.
@@ -76,7 +76,7 @@
* [trackName] of the track. The track is one of the rows visible in a perfetto trace inside
* SystemUI process.
*/
- inline fun <T> traceAsync(method: String, trackName: String, block: () -> T): T {
+ inline fun <T> traceAsync(trackName: String, method: String, block: () -> T): T {
val cookie = lastCookie.incrementAndGet()
Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_APP, trackName, method, cookie)
try {
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 4e0e8d0..4a6e53d 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -26,6 +26,7 @@
import android.view.View
import android.view.View.OnAttachStateChangeListener
import android.view.ViewTreeObserver
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
@@ -88,6 +89,15 @@
) {
var clock: ClockController? = null
set(value) {
+ smallClockOnAttachStateChangeListener?.let {
+ field?.smallClock?.view?.removeOnAttachStateChangeListener(it)
+ smallClockFrame?.viewTreeObserver
+ ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
+ }
+ largeClockOnAttachStateChangeListener?.let {
+ field?.largeClock?.view?.removeOnAttachStateChangeListener(it)
+ }
+
field = value
if (value != null) {
smallLogBuffer?.log(TAG, DEBUG, {}, { "New Clock" })
@@ -130,44 +140,62 @@
}
value.events.onWeatherDataChanged(it)
}
- value.smallClock.view.addOnAttachStateChangeListener(
+
+ smallClockOnAttachStateChangeListener =
object : OnAttachStateChangeListener {
var pastVisibility: Int? = null
override fun onViewAttachedToWindow(view: View?) {
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
if (view != null) {
- val smallClockFrame = view.parent as FrameLayout
- pastVisibility = smallClockFrame.visibility
- smallClockFrame.viewTreeObserver.addOnGlobalLayoutListener(
- ViewTreeObserver.OnGlobalLayoutListener {
- val currentVisibility = smallClockFrame.visibility
- if (pastVisibility != currentVisibility) {
- pastVisibility = currentVisibility
- // when small clock visible, recalculate bounds and sample
- if (currentVisibility == View.VISIBLE) {
- smallRegionSampler?.stopRegionSampler()
- smallRegionSampler?.startRegionSampler()
+ smallClockFrame = view.parent as FrameLayout
+ smallClockFrame?.let {frame ->
+ pastVisibility = frame.visibility
+ onGlobalLayoutListener = OnGlobalLayoutListener {
+ val currentVisibility = frame.visibility
+ if (pastVisibility != currentVisibility) {
+ pastVisibility = currentVisibility
+ // when small clock visible,
+ // recalculate bounds and sample
+ if (currentVisibility == View.VISIBLE) {
+ smallRegionSampler?.stopRegionSampler()
+ smallRegionSampler?.startRegionSampler()
+ }
}
}
- })
+ frame.viewTreeObserver
+ .addOnGlobalLayoutListener(onGlobalLayoutListener)
+ }
}
}
override fun onViewDetachedFromWindow(p0: View?) {
+ smallClockFrame?.viewTreeObserver
+ ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
}
- })
- value.largeClock.view.addOnAttachStateChangeListener(
+ }
+ value.smallClock.view
+ .addOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
+
+ largeClockOnAttachStateChangeListener =
object : OnAttachStateChangeListener {
override fun onViewAttachedToWindow(p0: View?) {
value.events.onTimeFormatChanged(DateFormat.is24HourFormat(context))
}
-
override fun onViewDetachedFromWindow(p0: View?) {
}
- })
+ }
+ value.largeClock.view
+ .addOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
}
}
+ @VisibleForTesting
+ var smallClockOnAttachStateChangeListener: OnAttachStateChangeListener? = null
+ @VisibleForTesting
+ var largeClockOnAttachStateChangeListener: OnAttachStateChangeListener? = null
+ private var smallClockFrame: FrameLayout? = null
+ private var onGlobalLayoutListener: OnGlobalLayoutListener? = null
+
private var isDozing = false
private set
@@ -307,7 +335,6 @@
return
}
isRegistered = true
-
broadcastDispatcher.registerReceiver(
localeBroadcastReceiver,
IntentFilter(Intent.ACTION_LOCALE_CHANGED)
@@ -346,6 +373,12 @@
largeRegionSampler?.stopRegionSampler()
smallTimeListener?.stop()
largeTimeListener?.stop()
+ clock?.smallClock?.view
+ ?.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
+ smallClockFrame?.viewTreeObserver
+ ?.removeOnGlobalLayoutListener(onGlobalLayoutListener)
+ clock?.largeClock?.view
+ ?.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
}
private fun updateTimeListeners() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 2135072..d615e18 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -21,6 +21,8 @@
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.annotation.Nullable;
import android.database.ContentObserver;
@@ -33,12 +35,15 @@
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.log.dagger.KeyguardClockLog;
@@ -58,6 +63,7 @@
import java.io.PrintWriter;
import java.util.Locale;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -99,8 +105,20 @@
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private boolean mOnlyClock = false;
+ private boolean mIsActiveDreamLockscreenHosted = false;
+ private FeatureFlags mFeatureFlags;
+ private KeyguardInteractor mKeyguardInteractor;
private final DelayableExecutor mUiExecutor;
private boolean mCanShowDoubleLineClock = true;
+ @VisibleForTesting
+ final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
+ (Boolean isLockscreenHosted) -> {
+ if (mIsActiveDreamLockscreenHosted == isLockscreenHosted) {
+ return;
+ }
+ mIsActiveDreamLockscreenHosted = isLockscreenHosted;
+ updateKeyguardStatusAreaVisibility();
+ };
private final ContentObserver mDoubleLineClockObserver = new ContentObserver(null) {
@Override
public void onChange(boolean change) {
@@ -137,7 +155,9 @@
@Main DelayableExecutor uiExecutor,
DumpManager dumpManager,
ClockEventController clockEventController,
- @KeyguardClockLog LogBuffer logBuffer) {
+ @KeyguardClockLog LogBuffer logBuffer,
+ KeyguardInteractor keyguardInteractor,
+ FeatureFlags featureFlags) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mClockRegistry = clockRegistry;
@@ -151,6 +171,8 @@
mClockEventController = clockEventController;
mLogBuffer = logBuffer;
mView.setLogBuffer(mLogBuffer);
+ mFeatureFlags = featureFlags;
+ mKeyguardInteractor = keyguardInteractor;
mClockChangedListener = new ClockRegistry.ClockChangeListener() {
@Override
@@ -191,6 +213,12 @@
mDumpManager.unregisterDumpable(getClass().getSimpleName()); // unregister previous clocks
mDumpManager.registerDumpable(getClass().getSimpleName(), this);
+
+ if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
+ mStatusArea = mView.findViewById(R.id.keyguard_status_area);
+ collectFlow(mStatusArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
+ mIsActiveDreamLockscreenHostedCallback);
+ }
}
@Override
@@ -524,6 +552,15 @@
}
}
+ private void updateKeyguardStatusAreaVisibility() {
+ if (mStatusArea != null) {
+ mUiExecutor.execute(() -> {
+ mStatusArea.setVisibility(
+ mIsActiveDreamLockscreenHosted ? View.INVISIBLE : View.VISIBLE);
+ });
+ }
+ }
+
/**
* Sets the clipChildren property on relevant views, to allow the smartspace to draw out of
* bounds during the unlock transition.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 99b5d52..38c07dc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -16,8 +16,10 @@
package com.android.keyguard;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
+import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.SystemClock;
import android.text.TextUtils;
@@ -74,6 +76,7 @@
BouncerKeyguardMessageArea mSecurityMessageDisplay;
private View mEcaView;
private ConstraintLayout mContainer;
+ @DevicePostureInt private int mLastDevicePosture = DEVICE_POSTURE_UNKNOWN;
public KeyguardPatternView(Context context) {
this(context, null);
@@ -95,14 +98,25 @@
mContext, android.R.interpolator.fast_out_linear_in));
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ updateMargins();
+ }
+
void onDevicePostureChanged(@DevicePostureInt int posture) {
+ mLastDevicePosture = posture;
+ updateMargins();
+ }
+
+ private void updateMargins() {
// Update the guideline based on the device posture...
float halfOpenPercentage =
mContext.getResources().getFloat(R.dimen.half_opened_bouncer_height_ratio);
ConstraintSet cs = new ConstraintSet();
cs.clone(mContainer);
- cs.setGuidelinePercent(R.id.pattern_top_guideline, posture == DEVICE_POSTURE_HALF_OPENED
+ cs.setGuidelinePercent(R.id.pattern_top_guideline,
+ mLastDevicePosture == DEVICE_POSTURE_HALF_OPENED
? halfOpenPercentage : 0.0f);
cs.applyTo(mContainer);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 3e16d55..794e694 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -77,6 +77,7 @@
});
}
mPasswordEntry.setUserActivityListener(this::onUserInput);
+ mView.onDevicePostureChanged(mPostureController.getDevicePosture());
mPostureController.addCallback(mPostureCallback);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 6853f81..42a4e72 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -793,8 +793,6 @@
void reloadColors() {
mViewMode.reloadColors();
- setBackgroundColor(Utils.getColorAttrDefaultColor(getContext(),
- com.android.internal.R.attr.materialColorSurface));
}
/** Handles density or font scale changes. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 458ca2b..f952337 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -79,17 +79,25 @@
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.scene.domain.interactor.SceneInteractor;
+import com.android.systemui.scene.shared.model.SceneContainerNames;
+import com.android.systemui.scene.shared.model.SceneKey;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.user.domain.interactor.UserInteractor;
import com.android.systemui.util.ViewController;
+import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import java.io.File;
import java.util.Optional;
import javax.inject.Inject;
+import javax.inject.Provider;
+
+import kotlinx.coroutines.Job;
/** Controller for {@link KeyguardSecurityContainer} */
@KeyguardBouncerScope
@@ -378,6 +386,10 @@
showPrimarySecurityScreen(false);
}
};
+ private final UserInteractor mUserInteractor;
+ private final Provider<SceneInteractor> mSceneInteractor;
+ private final Provider<JavaAdapter> mJavaAdapter;
+ @Nullable private Job mSceneTransitionCollectionJob;
@Inject
public KeyguardSecurityContainerController(KeyguardSecurityContainer view,
@@ -402,7 +414,10 @@
ViewMediatorCallback viewMediatorCallback,
AudioManager audioManager,
KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
- BouncerMessageInteractor bouncerMessageInteractor
+ BouncerMessageInteractor bouncerMessageInteractor,
+ Provider<JavaAdapter> javaAdapter,
+ UserInteractor userInteractor,
+ Provider<SceneInteractor> sceneInteractor
) {
super(view);
mLockPatternUtils = lockPatternUtils;
@@ -429,6 +444,9 @@
mAudioManager = audioManager;
mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
mBouncerMessageInteractor = bouncerMessageInteractor;
+ mUserInteractor = userInteractor;
+ mSceneInteractor = sceneInteractor;
+ mJavaAdapter = javaAdapter;
}
@Override
@@ -451,6 +469,24 @@
mView.setOnKeyListener(mOnKeyListener);
showPrimarySecurityScreen(false);
+
+ if (mFeatureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ // When the scene framework transitions from bouncer to gone, we dismiss the keyguard.
+ mSceneTransitionCollectionJob = mJavaAdapter.get().alwaysCollectFlow(
+ mSceneInteractor.get().sceneTransitions(SceneContainerNames.SYSTEM_UI_DEFAULT),
+ sceneTransitionModel -> {
+ if (sceneTransitionModel != null
+ && sceneTransitionModel.getFrom() == SceneKey.Bouncer.INSTANCE
+ && sceneTransitionModel.getTo() == SceneKey.Gone.INSTANCE) {
+ final int selectedUserId = mUserInteractor.getSelectedUserId();
+ showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ selectedUserId,
+ /* bypassSecondaryLockScreen= */ true,
+ mSecurityModel.getSecurityMode(selectedUserId));
+ }
+ });
+ }
}
@Override
@@ -459,6 +495,11 @@
mConfigurationController.removeCallback(mConfigurationListener);
mView.removeMotionEventListener(mGlobalTouchListener);
mUserSwitcherController.removeUserSwitchCallback(mUserSwitchCallback);
+
+ if (mSceneTransitionCollectionJob != null) {
+ mSceneTransitionCollectionJob.cancel(null);
+ mSceneTransitionCollectionJob = null;
+ }
}
/** */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 45744df..5e84a57 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -4543,13 +4543,18 @@
* Cancels all operations in the scheduler if it is hung for 10 seconds.
*/
public void startBiometricWatchdog() {
- if (mFaceManager != null && !isFaceAuthInteractorEnabled()) {
- mLogger.scheduleWatchdog("face");
- mFaceManager.scheduleWatchdog();
- }
- if (mFpm != null) {
- mLogger.scheduleWatchdog("fingerprint");
- mFpm.scheduleWatchdog();
- }
+ final boolean isFaceAuthInteractorEnabled = isFaceAuthInteractorEnabled();
+ mBackgroundExecutor.execute(() -> {
+ Trace.beginSection("#startBiometricWatchdog");
+ if (mFaceManager != null && !isFaceAuthInteractorEnabled) {
+ mLogger.scheduleWatchdog("face");
+ mFaceManager.scheduleWatchdog();
+ }
+ if (mFpm != null) {
+ mLogger.scheduleWatchdog("fingerprint");
+ mFpm.scheduleWatchdog();
+ }
+ Trace.endSection();
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 8ef6c2e..5459718 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -24,6 +24,7 @@
import static com.android.keyguard.LockIconView.ICON_UNLOCK;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.content.res.Configuration;
@@ -124,6 +125,7 @@
private int mActivePointerId = -1;
private boolean mIsDozing;
+ private boolean mIsActiveDreamLockscreenHosted;
private boolean mIsBouncerShowing;
private boolean mRunningFPS;
private boolean mCanDismissLockScreen;
@@ -165,6 +167,13 @@
updateVisibility();
};
+ @VisibleForTesting
+ final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
+ (Boolean isLockscreenHosted) -> {
+ mIsActiveDreamLockscreenHosted = isLockscreenHosted;
+ updateVisibility();
+ };
+
@Inject
public LockIconViewController(
@Nullable LockIconView view,
@@ -224,6 +233,11 @@
mDozeTransitionCallback);
collectFlow(mView, mKeyguardInteractor.isDozing(), mIsDozingCallback);
}
+
+ if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
+ collectFlow(mView, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
+ mIsActiveDreamLockscreenHostedCallback);
+ }
}
@Override
@@ -289,6 +303,11 @@
return;
}
+ if (mIsKeyguardShowing && mIsActiveDreamLockscreenHosted) {
+ mView.setVisibility(View.INVISIBLE);
+ return;
+ }
+
boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon
&& !mShowAodUnlockedIcon && !mShowAodLockIcon;
mShowLockIcon = !mCanDismissLockScreen && isLockScreen()
@@ -436,6 +455,7 @@
pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
pw.println(" mDefaultPaddingPx: " + mDefaultPaddingPx);
+ pw.println(" mIsActiveDreamLockscreenHosted: " + mIsActiveDreamLockscreenHosted);
if (mView != null) {
mView.dump(pw, args);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
index fd3c158..859e183 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
@@ -107,6 +107,10 @@
return mWindowMagnificationSettings.isSettingPanelShowing();
}
+ void setMagnificationScale(float scale) {
+ mWindowMagnificationSettings.setMagnificationScale(scale);
+ }
+
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
final int configDiff = newConfig.diff(mConfiguration);
@@ -160,8 +164,9 @@
*
* @param displayId The logical display id.
* @param scale Magnification scale value.
+ * @param updatePersistence whether the new scale should be persisted.
*/
- void onMagnifierScale(int displayId, float scale);
+ void onMagnifierScale(int displayId, float scale, boolean updatePersistence);
/**
* Called when magnification mode changed.
@@ -211,9 +216,9 @@
}
@Override
- public void onMagnifierScale(float scale) {
+ public void onMagnifierScale(float scale, boolean updatePersistence) {
mSettingsControllerCallback.onMagnifierScale(mDisplayId,
- A11Y_ACTION_SCALE_RANGE.clamp(scale));
+ A11Y_ACTION_SCALE_RANGE.clamp(scale), updatePersistence);
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 62ed9ca..69041d3 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -311,6 +311,10 @@
return;
}
scales.put(displayId, scale);
+
+ final MagnificationSettingsController magnificationSettingsController =
+ mMagnificationSettingsSupplier.get(displayId);
+ magnificationSettingsController.setMagnificationScale(scale);
}
@VisibleForTesting
@@ -330,9 +334,10 @@
}
@Override
- public void onPerformScaleAction(int displayId, float scale) {
+ public void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
if (mWindowMagnificationConnectionImpl != null) {
- mWindowMagnificationConnectionImpl.onPerformScaleAction(displayId, scale);
+ mWindowMagnificationConnectionImpl.onPerformScaleAction(
+ displayId, scale, updatePersistence);
}
}
@@ -384,9 +389,10 @@
}
@Override
- public void onMagnifierScale(int displayId, float scale) {
+ public void onMagnifierScale(int displayId, float scale, boolean updatePersistence) {
if (mWindowMagnificationConnectionImpl != null) {
- mWindowMagnificationConnectionImpl.onPerformScaleAction(displayId, scale);
+ mWindowMagnificationConnectionImpl.onPerformScaleAction(
+ displayId, scale, updatePersistence);
}
mA11yLogger.logThrottled(
MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_ZOOM_SLIDER_CHANGED
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
index f1d00ce2..928445b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationConnectionImpl.java
@@ -129,10 +129,10 @@
}
}
- void onPerformScaleAction(int displayId, float scale) {
+ void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
if (mConnectionCallback != null) {
try {
- mConnectionCallback.onPerformScaleAction(displayId, scale);
+ mConnectionCallback.onPerformScaleAction(displayId, scale, updatePersistence);
} catch (RemoteException e) {
Log.e(TAG, "Failed to inform performing scale action", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index e7eab7e..602f817 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -1491,13 +1491,9 @@
// Simulate tapping the drag view so it opens the Settings.
handleSingleTap(mDragView);
} else if (action == R.id.accessibility_action_zoom_in) {
- final float scale = mScale + A11Y_CHANGE_SCALE_DIFFERENCE;
- mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
- A11Y_ACTION_SCALE_RANGE.clamp(scale));
+ performScale(mScale + A11Y_CHANGE_SCALE_DIFFERENCE);
} else if (action == R.id.accessibility_action_zoom_out) {
- final float scale = mScale - A11Y_CHANGE_SCALE_DIFFERENCE;
- mWindowMagnifierCallback.onPerformScaleAction(mDisplayId,
- A11Y_ACTION_SCALE_RANGE.clamp(scale));
+ performScale(mScale - A11Y_CHANGE_SCALE_DIFFERENCE);
} else if (action == R.id.accessibility_action_move_up) {
move(0, -mSourceBounds.height());
} else if (action == R.id.accessibility_action_move_down) {
@@ -1512,5 +1508,11 @@
mWindowMagnifierCallback.onAccessibilityActionPerformed(mDisplayId);
return true;
}
+
+ private void performScale(float scale) {
+ scale = A11Y_ACTION_SCALE_RANGE.clamp(scale);
+ mWindowMagnifierCallback.onPerformScaleAction(
+ mDisplayId, scale, /* updatePersistence= */ true);
+ }
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 1e1d4b7..bb29d52 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -57,7 +57,6 @@
import android.widget.Switch;
import android.widget.TextView;
-import com.android.internal.accessibility.common.MagnificationConstants;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
@@ -89,14 +88,12 @@
private final MagnificationGestureDetector mGestureDetector;
private boolean mSingleTapDetected = false;
- @VisibleForTesting
- SeekBarWithIconButtonsView mZoomSeekbar;
+ private SeekBarWithIconButtonsView mZoomSeekbar;
private LinearLayout mAllowDiagonalScrollingView;
private TextView mAllowDiagonalScrollingTitle;
private Switch mAllowDiagonalScrollingSwitch;
private LinearLayout mPanelView;
private LinearLayout mSettingView;
- private LinearLayout mButtonView;
private ImageButton mSmallButton;
private ImageButton mMediumButton;
private ImageButton mLargeButton;
@@ -110,10 +107,11 @@
* magnitude = 10 means, for every 1 scale increase, 10 progress increase in seekbar.
*/
private int mSeekBarMagnitude;
+ private float mScale = SCALE_MIN_VALUE;
+
private WindowMagnificationSettingsCallback mCallback;
private ContentObserver mMagnificationCapabilityObserver;
- private ContentObserver mMagnificationScaleObserver;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -163,30 +161,20 @@
});
}
};
- mMagnificationScaleObserver = new ContentObserver(
- mContext.getMainThreadHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- setScaleSeekbar(getMagnificationScale());
- }
- };
}
private class ZoomSeekbarChangeListener implements
SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- float scale = (progress / (float) mSeekBarMagnitude) + SCALE_MIN_VALUE;
- // Update persisted scale only when scale >= PERSISTED_SCALE_MIN_VALUE const.
- // We assume if the scale is lower than the PERSISTED_SCALE_MIN_VALUE, there will be
- // no obvious magnification effect.
- if (scale >= MagnificationConstants.PERSISTED_SCALE_MIN_VALUE) {
- mSecureSettings.putFloatForUser(
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- scale,
- UserHandle.USER_CURRENT);
+ // Notify the service to update the magnifier scale only when the progress changed is
+ // triggered by user interaction on seekbar
+ if (fromUser) {
+ final float scale = transformProgressToScale(progress);
+ // We don't need to update the persisted scale when the seekbar progress is
+ // changing. The update should be triggered when the changing is ended.
+ mCallback.onMagnifierScale(scale, /* updatePersistence= */ false);
}
- mCallback.onMagnifierScale(scale);
}
@Override
@@ -201,7 +189,14 @@
@Override
public void onUserInteractionFinalized(SeekBar seekBar, @ControlUnitType int control) {
- // Do nothing
+ // Update the Settings persisted scale only when user interaction with seekbar ends
+ final int progress = seekBar.getProgress();
+ final float scale = transformProgressToScale(progress);
+ mCallback.onMagnifierScale(scale, /* updatePersistence= */ true);
+ }
+
+ private float transformProgressToScale(float progress) {
+ return (progress / (float) mSeekBarMagnitude) + SCALE_MIN_VALUE;
}
}
@@ -322,7 +317,6 @@
// Unregister observer before removing view
mSecureSettings.unregisterContentObserver(mMagnificationCapabilityObserver);
- mSecureSettings.unregisterContentObserver(mMagnificationScaleObserver);
mWindowManager.removeView(mSettingView);
mIsVisible = false;
if (resetPosition) {
@@ -387,10 +381,6 @@
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY,
mMagnificationCapabilityObserver,
UserHandle.USER_CURRENT);
- mSecureSettings.registerContentObserverForUser(
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- mMagnificationScaleObserver,
- UserHandle.USER_CURRENT);
// Exclude magnification switch button from system gesture area.
setSystemGestureExclusion();
@@ -430,11 +420,21 @@
UserHandle.USER_CURRENT);
}
+ /**
+ * Only called from outside to notify the controlling magnifier scale changed
+ *
+ * @param scale The new controlling magnifier scale
+ */
+ public void setMagnificationScale(float scale) {
+ mScale = scale;
+
+ if (isSettingPanelShowing()) {
+ setScaleSeekbar(scale);
+ }
+ }
+
private float getMagnificationScale() {
- return mSecureSettings.getFloatForUser(
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- SCALE_MIN_VALUE,
- UserHandle.USER_CURRENT);
+ return mScale;
}
private void updateUIControlsIfNeeded() {
@@ -523,10 +523,7 @@
mZoomSeekbar.setMax((int) (mZoomSeekbar.getChangeMagnitude()
* (SCALE_MAX_VALUE - SCALE_MIN_VALUE)));
mSeekBarMagnitude = mZoomSeekbar.getChangeMagnitude();
- float scale = mSecureSettings.getFloatForUser(
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 0,
- UserHandle.USER_CURRENT);
- setScaleSeekbar(scale);
+ setScaleSeekbar(mScale);
mZoomSeekbar.setOnSeekBarWithIconButtonsChangeListener(new ZoomSeekbarChangeListener());
mAllowDiagonalScrollingView =
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java
index 3dbff5d..2eee7a6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettingsCallback.java
@@ -52,8 +52,9 @@
* Called when set magnification scale.
*
* @param scale Magnification scale value.
+ * @param updatePersistence whether the scale should be persisted
*/
- void onMagnifierScale(float scale);
+ void onMagnifierScale(float scale, boolean updatePersistence);
/**
* Called when magnification mode changed.
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
index e18161d..a25e9a2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
@@ -44,8 +44,9 @@
*
* @param displayId The logical display id.
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ * @param updatePersistence whether the scale should be persisted
*/
- void onPerformScaleAction(int displayId, float scale);
+ void onPerformScaleAction(int displayId, float scale, boolean updatePersistence);
/**
* Called when the accessibility action is performed.
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
index 0b25184..43fb363 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/data/repository/AuthenticationRepository.kt
@@ -14,25 +14,39 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.authentication.data.repository
+import com.android.internal.widget.LockPatternChecker
import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationResultModel
+import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.time.SystemClock
import dagger.Binds
import dagger.Module
import java.util.function.Function
import javax.inject.Inject
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@@ -57,11 +71,17 @@
*/
val isBypassEnabled: StateFlow<Boolean>
- /**
- * Number of consecutively failed authentication attempts. This resets to `0` when
- * authentication succeeds.
- */
- val failedAuthenticationAttempts: StateFlow<Int>
+ /** Whether the auto confirm feature is enabled for the currently-selected user. */
+ val isAutoConfirmEnabled: StateFlow<Boolean>
+
+ /** The length of the PIN for which we should show a hint. */
+ val hintedPinLength: Int
+
+ /** Whether the pattern should be visible for the currently-selected user. */
+ val isPatternVisible: StateFlow<Boolean>
+
+ /** The current throttling state, as cached via [setThrottling]. */
+ val throttling: StateFlow<AuthenticationThrottlingModel>
/**
* Returns the currently-configured authentication method. This determines how the
@@ -69,11 +89,48 @@
*/
suspend fun getAuthenticationMethod(): AuthenticationMethodModel
+ /** Returns the length of the PIN or `0` if the current auth method is not PIN. */
+ suspend fun getPinLength(): Int
+
+ /**
+ * Returns whether the lockscreen is enabled.
+ *
+ * When the lockscreen is not enabled, it shouldn't show in cases when the authentication method
+ * is considered not secure (for example, "swipe" is considered to be "none").
+ */
+ suspend fun isLockscreenEnabled(): Boolean
+
/** See [isBypassEnabled]. */
fun setBypassEnabled(isBypassEnabled: Boolean)
- /** See [failedAuthenticationAttempts]. */
- fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int)
+ /** Reports an authentication attempt. */
+ suspend fun reportAuthenticationAttempt(isSuccessful: Boolean)
+
+ /** Returns the current number of failed authentication attempts. */
+ suspend fun getFailedAuthenticationAttemptCount(): Int
+
+ /**
+ * Returns the timestamp for when the current throttling will end, allowing the user to attempt
+ * authentication again.
+ *
+ * Note that this is in milliseconds and it matches [SystemClock.elapsedRealtime].
+ */
+ suspend fun getThrottlingEndTimestamp(): Long
+
+ /** Sets the cached throttling state, updating the [throttling] flow. */
+ fun setThrottling(throttlingModel: AuthenticationThrottlingModel)
+
+ /**
+ * Sets the throttling timeout duration (time during which the user should not be allowed to
+ * attempt authentication).
+ */
+ suspend fun setThrottleDuration(durationMs: Int)
+
+ /**
+ * Checks the given [LockscreenCredential] to see if it's correct, returning an
+ * [AuthenticationResultModel] representing what happened.
+ */
+ suspend fun checkCredential(credential: LockscreenCredential): AuthenticationResultModel
}
class AuthenticationRepositoryImpl
@@ -83,8 +140,8 @@
private val getSecurityMode: Function<Int, KeyguardSecurityModel.SecurityMode>,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val userRepository: UserRepository,
- private val lockPatternUtils: LockPatternUtils,
keyguardRepository: KeyguardRepository,
+ private val lockPatternUtils: LockPatternUtils,
) : AuthenticationRepository {
override val isUnlocked: StateFlow<Boolean> =
@@ -94,54 +151,140 @@
initialValue = false,
)
+ override suspend fun isLockscreenEnabled(): Boolean {
+ return withContext(backgroundDispatcher) {
+ val selectedUserId = userRepository.selectedUserId
+ !lockPatternUtils.isLockPatternEnabled(selectedUserId)
+ }
+ }
+
private val _isBypassEnabled = MutableStateFlow(false)
override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled.asStateFlow()
- private val _failedAuthenticationAttempts = MutableStateFlow(0)
- override val failedAuthenticationAttempts: StateFlow<Int> =
- _failedAuthenticationAttempts.asStateFlow()
+ override val isAutoConfirmEnabled: StateFlow<Boolean> =
+ userRepository.selectedUserInfo
+ .map { it.id }
+ .flatMapLatest { userId ->
+ flow { emit(lockPatternUtils.isAutoPinConfirmEnabled(userId)) }
+ .flowOn(backgroundDispatcher)
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = true,
+ )
+
+ override val hintedPinLength: Int = LockPatternUtils.MIN_AUTO_PIN_REQUIREMENT_LENGTH
+
+ override val isPatternVisible: StateFlow<Boolean> =
+ userRepository.selectedUserInfo
+ .map { it.id }
+ .flatMapLatest { userId ->
+ flow { emit(lockPatternUtils.isVisiblePatternEnabled(userId)) }
+ .flowOn(backgroundDispatcher)
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = true,
+ )
+
+ private val _throttling = MutableStateFlow(AuthenticationThrottlingModel())
+ override val throttling: StateFlow<AuthenticationThrottlingModel> = _throttling.asStateFlow()
+
+ private val UserRepository.selectedUserId: Int
+ get() = getSelectedUserInfo().id
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
return withContext(backgroundDispatcher) {
- val selectedUserId = userRepository.getSelectedUserInfo().id
+ val selectedUserId = userRepository.selectedUserId
when (getSecurityMode.apply(selectedUserId)) {
KeyguardSecurityModel.SecurityMode.PIN,
- KeyguardSecurityModel.SecurityMode.SimPin ->
- AuthenticationMethodModel.Pin(
- code = listOf(1, 2, 3, 4), // TODO(b/280883900): remove this
- autoConfirm = lockPatternUtils.isAutoPinConfirmEnabled(selectedUserId),
- )
- KeyguardSecurityModel.SecurityMode.Password,
- KeyguardSecurityModel.SecurityMode.SimPuk ->
- AuthenticationMethodModel.Password(
- password = "password", // TODO(b/280883900): remove this
- )
- KeyguardSecurityModel.SecurityMode.Pattern ->
- AuthenticationMethodModel.Pattern(
- coordinates =
- listOf(
- AuthenticationMethodModel.Pattern.PatternCoordinate(2, 0),
- AuthenticationMethodModel.Pattern.PatternCoordinate(2, 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(2, 2),
- AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(0, 0),
- AuthenticationMethodModel.Pattern.PatternCoordinate(0, 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(0, 2),
- ), // TODO(b/280883900): remove this
- )
+ KeyguardSecurityModel.SecurityMode.SimPin,
+ KeyguardSecurityModel.SecurityMode.SimPuk -> AuthenticationMethodModel.Pin
+ KeyguardSecurityModel.SecurityMode.Password -> AuthenticationMethodModel.Password
+ KeyguardSecurityModel.SecurityMode.Pattern -> AuthenticationMethodModel.Pattern
KeyguardSecurityModel.SecurityMode.None -> AuthenticationMethodModel.None
KeyguardSecurityModel.SecurityMode.Invalid -> error("Invalid security mode!")
- null -> error("Invalid security is null!")
}
}
}
+ override suspend fun getPinLength(): Int {
+ return withContext(backgroundDispatcher) {
+ val selectedUserId = userRepository.selectedUserId
+ lockPatternUtils.getPinLength(selectedUserId)
+ }
+ }
+
override fun setBypassEnabled(isBypassEnabled: Boolean) {
_isBypassEnabled.value = isBypassEnabled
}
- override fun setFailedAuthenticationAttempts(failedAuthenticationAttempts: Int) {
- _failedAuthenticationAttempts.value = failedAuthenticationAttempts
+ override suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) {
+ val selectedUserId = userRepository.selectedUserId
+ withContext(backgroundDispatcher) {
+ if (isSuccessful) {
+ lockPatternUtils.reportSuccessfulPasswordAttempt(selectedUserId)
+ } else {
+ lockPatternUtils.reportFailedPasswordAttempt(selectedUserId)
+ }
+ }
+ }
+
+ override suspend fun getFailedAuthenticationAttemptCount(): Int {
+ return withContext(backgroundDispatcher) {
+ val selectedUserId = userRepository.selectedUserId
+ lockPatternUtils.getCurrentFailedPasswordAttempts(selectedUserId)
+ }
+ }
+
+ override suspend fun getThrottlingEndTimestamp(): Long {
+ return withContext(backgroundDispatcher) {
+ val selectedUserId = userRepository.selectedUserId
+ lockPatternUtils.getLockoutAttemptDeadline(selectedUserId)
+ }
+ }
+
+ override fun setThrottling(throttlingModel: AuthenticationThrottlingModel) {
+ _throttling.value = throttlingModel
+ }
+
+ override suspend fun setThrottleDuration(durationMs: Int) {
+ withContext(backgroundDispatcher) {
+ lockPatternUtils.setLockoutAttemptDeadline(
+ userRepository.selectedUserId,
+ durationMs,
+ )
+ }
+ }
+
+ override suspend fun checkCredential(
+ credential: LockscreenCredential
+ ): AuthenticationResultModel {
+ return suspendCoroutine { continuation ->
+ LockPatternChecker.checkCredential(
+ lockPatternUtils,
+ credential,
+ userRepository.selectedUserId,
+ object : LockPatternChecker.OnCheckCallback {
+ override fun onChecked(matched: Boolean, throttleTimeoutMs: Int) {
+ continuation.resume(
+ AuthenticationResultModel(
+ isSuccessful = matched,
+ throttleDurationMs = throttleTimeoutMs,
+ )
+ )
+ }
+
+ override fun onCancelled() {
+ continuation.resume(AuthenticationResultModel(isSuccessful = false))
+ }
+
+ override fun onEarlyMatched() = Unit
+ }
+ )
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index 15e579d..82674bf 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -16,25 +16,43 @@
package com.android.systemui.authentication.domain.interactor
-import android.app.admin.DevicePolicyManager
+import com.android.internal.widget.LockPatternView
+import com.android.internal.widget.LockscreenCredential
import com.android.systemui.authentication.data.repository.AuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
+import kotlin.math.max
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/** Hosts application business logic related to authentication. */
@SysUISingleton
class AuthenticationInteractor
@Inject
constructor(
- @Application applicationScope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
private val repository: AuthenticationRepository,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val userRepository: UserRepository,
+ private val clock: SystemClock,
) {
/**
* Whether the device is unlocked.
@@ -67,18 +85,66 @@
*/
val isBypassEnabled: StateFlow<Boolean> = repository.isBypassEnabled
+ /** The current authentication throttling state, only meaningful if [isThrottled] is `true`. */
+ val throttling: StateFlow<AuthenticationThrottlingModel> = repository.throttling
+
/**
- * Number of consecutively failed authentication attempts. This resets to `0` when
- * authentication succeeds.
+ * Whether currently throttled and the user has to wait before being able to try another
+ * authentication attempt.
*/
- val failedAuthenticationAttempts: StateFlow<Int> = repository.failedAuthenticationAttempts
+ val isThrottled: StateFlow<Boolean> =
+ throttling
+ .map { it.remainingMs > 0 }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = throttling.value.remainingMs > 0,
+ )
+
+ /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
+ val hintedPinLength: StateFlow<Int?> =
+ flow { emit(repository.getPinLength()) }
+ .map { currentPinLength ->
+ // Hinting is enabled for 6-digit codes only
+ currentPinLength.takeIf { repository.hintedPinLength == it }
+ }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = null,
+ )
+
+ /** Whether the auto confirm feature is enabled for the currently-selected user. */
+ val isAutoConfirmEnabled: StateFlow<Boolean> = repository.isAutoConfirmEnabled
+
+ /** Whether the pattern should be visible for the currently-selected user. */
+ val isPatternVisible: StateFlow<Boolean> = repository.isPatternVisible
+
+ private var throttlingCountdownJob: Job? = null
+
+ init {
+ applicationScope.launch {
+ userRepository.selectedUserInfo
+ .map { it.id }
+ .distinctUntilChanged()
+ .collect { onSelectedUserChanged() }
+ }
+ }
/**
* Returns the currently-configured authentication method. This determines how the
* authentication challenge is completed in order to unlock an otherwise locked device.
*/
suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
- return repository.getAuthenticationMethod()
+ val authMethod = repository.getAuthenticationMethod()
+ return if (
+ authMethod is AuthenticationMethodModel.None && repository.isLockscreenEnabled()
+ ) {
+ // We treat "None" as "Swipe" when the lockscreen is enabled.
+ AuthenticationMethodModel.Swipe
+ } else {
+ authMethod
+ }
}
/**
@@ -104,39 +170,52 @@
* authentication failed, `null` if the check was not performed.
*/
suspend fun authenticate(input: List<Any>, tryAutoConfirm: Boolean = false): Boolean? {
- val authMethod = getAuthenticationMethod()
- if (tryAutoConfirm) {
- if ((authMethod as? AuthenticationMethodModel.Pin)?.autoConfirm != true) {
- // Do not attempt to authenticate unless the PIN lock is set to auto-confirm.
- return null
- }
-
- if (input.size < authMethod.code.size) {
- // Do not attempt to authenticate if the PIN has not yet the required amount of
- // digits. This intentionally only skip for shorter PINs; if the PIN is longer, the
- // layer above might have throttled this check, and the PIN should be rejected via
- // the auth code below.
- return null
- }
+ if (input.isEmpty()) {
+ throw IllegalArgumentException("Input was empty!")
}
- val isSuccessful =
- when (authMethod) {
- is AuthenticationMethodModel.Pin -> input.asCode() == authMethod.code
- is AuthenticationMethodModel.Password -> input.asPassword() == authMethod.password
- is AuthenticationMethodModel.Pattern -> input.asPattern() == authMethod.coordinates
- else -> true
+ val skipCheck =
+ when {
+ // We're being throttled, the UI layer should not have called this; skip the
+ // attempt.
+ isThrottled.value -> true
+ // Auto-confirm attempt when the feature is not enabled; skip the attempt.
+ tryAutoConfirm && !isAutoConfirmEnabled.value -> true
+ // Auto-confirm should skip the attempt if the pin entered is too short.
+ tryAutoConfirm && input.size < repository.getPinLength() -> true
+ else -> false
}
+ if (skipCheck) {
+ return null
+ }
- if (isSuccessful) {
- repository.setFailedAuthenticationAttempts(0)
- } else {
- repository.setFailedAuthenticationAttempts(
- repository.failedAuthenticationAttempts.value + 1
+ // Attempt to authenticate:
+ val authMethod = getAuthenticationMethod()
+ val credential = authMethod.createCredential(input) ?: return null
+ val authenticationResult = repository.checkCredential(credential)
+ credential.zeroize()
+
+ if (authenticationResult.isSuccessful || !tryAutoConfirm) {
+ repository.reportAuthenticationAttempt(
+ isSuccessful = authenticationResult.isSuccessful,
)
}
- return isSuccessful
+ // Check if we need to throttle and, if so, kick off the throttle countdown:
+ if (!authenticationResult.isSuccessful && authenticationResult.throttleDurationMs > 0) {
+ repository.setThrottleDuration(
+ durationMs = authenticationResult.throttleDurationMs,
+ )
+ startThrottlingCountdown()
+ }
+
+ if (authenticationResult.isSuccessful) {
+ // Since authentication succeeded, we should refresh throttling to make sure that our
+ // state is completely reflecting the upstream source of truth.
+ refreshThrottling()
+ }
+
+ return authenticationResult.isSuccessful
}
/** See [isBypassEnabled]. */
@@ -144,44 +223,67 @@
repository.setBypassEnabled(!repository.isBypassEnabled.value)
}
- companion object {
- /**
- * Returns a PIN code from the given list. It's assumed the given list elements are all
- * [Int] in the range [0-9].
- */
- private fun List<Any>.asCode(): List<Int>? {
- if (isEmpty() || size > DevicePolicyManager.MAX_PASSWORD_LENGTH) {
- return null
- }
-
- return map {
- require(it is Int && it in 0..9) {
- "Pin is required to be Int in range [0..9], but got $it"
+ /** Starts refreshing the throttling state every second. */
+ private suspend fun startThrottlingCountdown() {
+ cancelCountdown()
+ throttlingCountdownJob =
+ applicationScope.launch {
+ while (refreshThrottling() > 0) {
+ delay(1.seconds.inWholeMilliseconds)
}
- it
}
- }
+ }
- /**
- * Returns a password from the given list. It's assumed the given list elements are all
- * [Char].
- */
- private fun List<Any>.asPassword(): String {
- val anyList = this
- return buildString { anyList.forEach { append(it as Char) } }
- }
+ /** Cancels any throttling state countdown started in [startThrottlingCountdown]. */
+ private fun cancelCountdown() {
+ throttlingCountdownJob?.cancel()
+ throttlingCountdownJob = null
+ }
- /**
- * Returns a list of [AuthenticationMethodModel.Pattern.PatternCoordinate] from the given
- * list. It's assumed the given list elements are all
- * [AuthenticationMethodModel.Pattern.PatternCoordinate].
- */
- private fun List<Any>.asPattern():
- List<AuthenticationMethodModel.Pattern.PatternCoordinate> {
- val anyList = this
- return buildList {
- anyList.forEach { add(it as AuthenticationMethodModel.Pattern.PatternCoordinate) }
- }
+ /** Notifies that the currently-selected user has changed. */
+ private suspend fun onSelectedUserChanged() {
+ cancelCountdown()
+ if (refreshThrottling() > 0) {
+ startThrottlingCountdown()
+ }
+ }
+
+ /**
+ * Refreshes the throttling state, hydrating the repository with the latest state.
+ *
+ * @return The remaining time for the current throttling countdown, in milliseconds or `0` if
+ * not being throttled.
+ */
+ private suspend fun refreshThrottling(): Long {
+ return withContext(backgroundDispatcher) {
+ val failedAttemptCount = async { repository.getFailedAuthenticationAttemptCount() }
+ val deadline = async { repository.getThrottlingEndTimestamp() }
+ val remainingMs = max(0, deadline.await() - clock.elapsedRealtime())
+ repository.setThrottling(
+ AuthenticationThrottlingModel(
+ failedAttemptCount = failedAttemptCount.await(),
+ remainingMs = remainingMs.toInt(),
+ ),
+ )
+ remainingMs
+ }
+ }
+
+ private fun AuthenticationMethodModel.createCredential(
+ input: List<Any>
+ ): LockscreenCredential? {
+ return when (this) {
+ is AuthenticationMethodModel.Pin ->
+ LockscreenCredential.createPin(input.joinToString(""))
+ is AuthenticationMethodModel.Password ->
+ LockscreenCredential.createPassword(input.joinToString(""))
+ is AuthenticationMethodModel.Pattern ->
+ LockscreenCredential.createPattern(
+ input
+ .map { it as AuthenticationMethodModel.Pattern.PatternCoordinate }
+ .map { LockPatternView.Cell.of(it.y, it.x) }
+ )
+ else -> null
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
index 1016b6b..97c6697 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationMethodModel.kt
@@ -16,8 +16,6 @@
package com.android.systemui.authentication.shared.model
-import androidx.annotation.VisibleForTesting
-
/** Enumerates all known authentication methods. */
sealed class AuthenticationMethodModel(
/**
@@ -34,30 +32,11 @@
/** The most basic authentication method. The lock screen can be swiped away when displayed. */
object Swipe : AuthenticationMethodModel(isSecure = false)
- /**
- * Authentication method using a PIN.
- *
- * In practice, a pin is restricted to 16 decimal digits , see
- * [android.app.admin.DevicePolicyManager.MAX_PASSWORD_LENGTH]
- */
- data class Pin(val code: List<Int>, val autoConfirm: Boolean) :
- AuthenticationMethodModel(isSecure = true) {
+ object Pin : AuthenticationMethodModel(isSecure = true)
- /** Convenience constructor for tests only. */
- @VisibleForTesting
- constructor(
- code: Long,
- autoConfirm: Boolean = false
- ) : this(code.toString(10).map { it - '0' }, autoConfirm) {}
- }
+ object Password : AuthenticationMethodModel(isSecure = true)
- data class Password(val password: String) : AuthenticationMethodModel(isSecure = true)
-
- data class Pattern(
- val coordinates: List<PatternCoordinate>,
- val isPatternVisible: Boolean = true,
- ) : AuthenticationMethodModel(isSecure = true) {
-
+ object Pattern : AuthenticationMethodModel(isSecure = true) {
data class PatternCoordinate(
val x: Int,
val y: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationResultModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationResultModel.kt
new file mode 100644
index 0000000..f2a3e74
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationResultModel.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.authentication.shared.model
+
+/** Models the result of an authentication attempt. */
+data class AuthenticationResultModel(
+ /** Whether authentication was successful. */
+ val isSuccessful: Boolean = false,
+ /** If [isSuccessful] is `false`, how long the user must wait before trying again. */
+ val throttleDurationMs: Int = 0,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationThrottlingModel.kt b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationThrottlingModel.kt
new file mode 100644
index 0000000..d0d398e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/authentication/shared/model/AuthenticationThrottlingModel.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.authentication.shared.model
+
+/** Models a state for throttling the next authentication attempt. */
+data class AuthenticationThrottlingModel(
+
+ /** Number of failed authentication attempts so far. If not throttling this will be `0`. */
+ val failedAttemptCount: Int = 0,
+
+ /**
+ * Remaining amount of time, in milliseconds, before another authentication attempt can be done.
+ * If not throttling this will be `0`.
+ *
+ * This number is changed throughout the timeout.
+ */
+ val remainingMs: Int = 0,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index cd8f04d..ed4b91c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -737,7 +737,7 @@
});
mUseCredentialButton.setOnClickListener((view) -> {
- startTransitionToCredentialUI();
+ startTransitionToCredentialUI(false /* isError */);
});
mConfirmButton.setOnClickListener((view) -> {
@@ -768,9 +768,12 @@
/**
* Kicks off the animation process and invokes the callback.
+ *
+ * @param isError if this was triggered due to an error and not a user action (unused,
+ * previously for haptics).
*/
@Override
- public void startTransitionToCredentialUI() {
+ public void startTransitionToCredentialUI(boolean isError) {
updateSize(AuthDialog.SIZE_LARGE);
mCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt
index 631511c..68db564 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt
@@ -38,7 +38,7 @@
fun onHelp(@BiometricAuthenticator.Modality modality: Int, help: String)
- fun startTransitionToCredentialUI()
+ fun startTransitionToCredentialUI(isError: Boolean)
fun requestLayout()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index d8348ed..7a2f244 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -801,9 +801,9 @@
}
@Override
- public void animateToCredentialUI() {
+ public void animateToCredentialUI(boolean isError) {
if (mBiometricView != null) {
- mBiometricView.startTransitionToCredentialUI();
+ mBiometricView.startTransitionToCredentialUI(isError);
} else {
Log.e(TAG, "animateToCredentialUI(): mBiometricView is null");
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 76e48e9..3df7ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -85,7 +85,6 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.data.repository.BiometricType;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
@@ -185,18 +184,6 @@
private final @Background DelayableExecutor mBackgroundExecutor;
private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
- private final VibratorHelper mVibratorHelper;
-
- private void vibrateSuccess(int modality) {
- mVibratorHelper.vibrateAuthSuccess(
- getClass().getSimpleName() + ", modality = " + modality + "BP::success");
- }
-
- private void vibrateError(int modality) {
- mVibratorHelper.vibrateAuthError(
- getClass().getSimpleName() + ", modality = " + modality + "BP::error");
- }
-
@VisibleForTesting
final TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
@@ -784,7 +771,6 @@
@NonNull InteractionJankMonitor jankMonitor,
@Main Handler handler,
@Background DelayableExecutor bgExecutor,
- @NonNull VibratorHelper vibrator,
@NonNull UdfpsUtils udfpsUtils) {
mContext = context;
mFeatureFlags = featureFlags;
@@ -806,7 +792,6 @@
mUdfpsEnrolledForUser = new SparseBooleanArray();
mSfpsEnrolledForUser = new SparseBooleanArray();
mFaceEnrolledForUser = new SparseBooleanArray();
- mVibratorHelper = vibrator;
mUdfpsUtils = udfpsUtils;
mApplicationCoroutineScope = applicationCoroutineScope;
@@ -995,8 +980,6 @@
public void onBiometricAuthenticated(@Modality int modality) {
if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: ");
- vibrateSuccess(modality);
-
if (mCurrentDialog != null) {
mCurrentDialog.onAuthenticationSucceeded(modality);
} else {
@@ -1093,8 +1076,6 @@
Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode));
}
- vibrateError(modality);
-
final boolean isLockout = (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT)
|| (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
@@ -1111,9 +1092,10 @@
if (mCurrentDialog != null) {
if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
- mCurrentDialog.animateToCredentialUI();
+ mCurrentDialog.animateToCredentialUI(true /* isError */);
} else if (isSoftError) {
- final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
+ final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
+ || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT)
? getNotRecognizedString(modality)
: getErrorString(modality, error, vendorCode);
if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index b6eabfa..3cfc6f2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -162,7 +162,7 @@
/**
* Animate to credential UI. Typically called after biometric is locked out.
*/
- void animateToCredentialUI();
+ void animateToCredentialUI(boolean isError);
/**
* @return true if device credential is allowed.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
index d92c217..ac4b717 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt
@@ -23,7 +23,7 @@
import com.android.systemui.biometrics.data.repository.PromptRepository
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
-import com.android.systemui.biometrics.domain.model.BiometricUserInfo
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.dagger.qualifiers.Background
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
index be99dd9..bb87dca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt
@@ -25,7 +25,7 @@
import com.android.systemui.biometrics.domain.model.BiometricModalities
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
-import com.android.systemui.biometrics.domain.model.BiometricUserInfo
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.biometrics.shared.model.PromptKind
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
index 75de47d..caebc30 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt
@@ -1,6 +1,7 @@
package com.android.systemui.biometrics.domain.model
import android.hardware.biometrics.PromptInfo
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
/**
* Preferences for BiometricPrompt, such as title & description, that are immutable while the prompt
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricUserInfo.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricUserInfo.kt
deleted file mode 100644
index 08da04d..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricUserInfo.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.android.systemui.biometrics.domain.model
-
-/** Metadata about the current user BiometricPrompt is being shown to. */
-data class BiometricUserInfo(
- val userId: Int,
- val deviceCredentialOwnerId: Int = userId,
-)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricModality.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricModality.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricModality.kt
rename to packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricModality.kt
index 3197c09..fb580ca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricModality.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricModality.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.biometrics.domain.model
+package com.android.systemui.biometrics.shared.model
import android.hardware.biometrics.BiometricAuthenticator
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
new file mode 100644
index 0000000..39689ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/BiometricUserInfo.kt
@@ -0,0 +1,12 @@
+package com.android.systemui.biometrics.shared.model
+
+/**
+ * Metadata about the current user BiometricPrompt is being shown to.
+ *
+ * If the user's fallback credential is owned by another profile user the [deviceCredentialOwnerId]
+ * will differ from the user's [userId].
+ */
+data class BiometricUserInfo(
+ val userId: Int,
+ val deviceCredentialOwnerId: Int = userId,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 6a7431e..e5a4d1a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -46,9 +46,9 @@
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.domain.model.BiometricModalities
-import com.android.systemui.biometrics.domain.model.BiometricModality
-import com.android.systemui.biometrics.domain.model.asBiometricModality
+import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.PromptKind
+import com.android.systemui.biometrics.shared.model.asBiometricModality
import com.android.systemui.biometrics.ui.BiometricPromptLayout
import com.android.systemui.biometrics.ui.viewmodel.FingerprintStartMode
import com.android.systemui.biometrics.ui.viewmodel.PromptMessage
@@ -396,7 +396,6 @@
private var lifecycleScope: CoroutineScope? = null
private var modalities: BiometricModalities = BiometricModalities()
- private var faceFailedAtLeastOnce = false
private var legacyCallback: Callback? = null
override var legacyIconController: AuthIconController? = null
@@ -476,19 +475,15 @@
viewModel.ensureFingerprintHasStarted(isDelayed = true)
applicationScope.launch {
- val suppress =
- modalities.hasFaceAndFingerprint &&
- (failedModality == BiometricModality.Face) &&
- faceFailedAtLeastOnce
- if (failedModality == BiometricModality.Face) {
- faceFailedAtLeastOnce = true
- }
-
viewModel.showTemporaryError(
failureReason,
messageAfterError = modalities.asDefaultHelpMessage(applicationContext),
authenticateAfterError = modalities.hasFingerprint,
- suppressIfErrorShowing = suppress,
+ suppressIf = { currentMessage ->
+ modalities.hasFaceAndFingerprint &&
+ failedModality == BiometricModality.Face &&
+ currentMessage.isError
+ },
failedModality = failedModality,
)
}
@@ -501,11 +496,10 @@
}
applicationScope.launch {
- val suppress =
- modalities.hasFaceAndFingerprint && (errorModality == BiometricModality.Face)
viewModel.showTemporaryError(
error,
- suppressIfErrorShowing = suppress,
+ messageAfterError = modalities.asDefaultHelpMessage(applicationContext),
+ authenticateAfterError = modalities.hasFingerprint,
)
delay(BiometricPrompt.HIDE_DIALOG_DELAY.toLong())
legacyCallback?.onAction(Callback.ACTION_ERROR)
@@ -522,6 +516,8 @@
viewModel.showTemporaryError(
help,
messageAfterError = modalities.asDefaultHelpMessage(applicationContext),
+ authenticateAfterError = modalities.hasFingerprint,
+ hapticFeedback = false,
)
}
}
@@ -534,7 +530,7 @@
else -> false
}
- override fun startTransitionToCredentialUI() {
+ override fun startTransitionToCredentialUI(isError: Boolean) {
applicationScope.launch {
viewModel.onSwitchToCredential()
legacyCallback?.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
index 6fb8e34..c27d7152 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
@@ -1,5 +1,6 @@
package com.android.systemui.biometrics.ui.binder
+import android.os.UserHandle
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
@@ -9,6 +10,7 @@
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R
import com.android.systemui.biometrics.ui.CredentialPasswordView
@@ -16,6 +18,8 @@
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
/** Sub-binder for the [CredentialPasswordView]. */
@@ -35,31 +39,22 @@
val onBackInvokedCallback = OnBackInvokedCallback { host.onCredentialAborted() }
view.repeatWhenAttached {
+ // the header info never changes - do it early
+ val header = viewModel.header.first()
+ passwordField.setTextOperationUser(UserHandle.of(header.user.deviceCredentialOwnerId))
+ viewModel.inputFlags.firstOrNull()?.let { flags -> passwordField.inputType = flags }
if (requestFocusForInput) {
passwordField.requestFocus()
passwordField.scheduleShowSoftInput()
}
+ passwordField.setOnEditorActionListener(
+ OnImeSubmitListener { text ->
+ lifecycleScope.launch { viewModel.checkCredential(text, header) }
+ }
+ )
+ passwordField.setOnKeyListener(OnBackButtonListener(onBackInvokedCallback))
repeatOnLifecycle(Lifecycle.State.STARTED) {
- // observe credential validation attempts and submit/cancel buttons
- launch {
- viewModel.header.collect { header ->
- passwordField.setTextOperationUser(header.user)
- passwordField.setOnEditorActionListener(
- OnImeSubmitListener { text ->
- launch { viewModel.checkCredential(text, header) }
- }
- )
- passwordField.setOnKeyListener(OnBackButtonListener(onBackInvokedCallback))
- }
- }
-
- launch {
- viewModel.inputFlags.collect { flags ->
- flags?.let { passwordField.inputType = it }
- }
- }
-
// dismiss on a valid credential check
launch {
viewModel.validatedAttestation.collect { attestation ->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
index a64798c..3257f20 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialHeaderViewModel.kt
@@ -1,11 +1,11 @@
package com.android.systemui.biometrics.ui.viewmodel
import android.graphics.drawable.Drawable
-import android.os.UserHandle
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
/** View model for the top-level header / info area of BiometricPrompt. */
interface CredentialHeaderViewModel {
- val user: UserHandle
+ val user: BiometricUserInfo
val title: String
val subtitle: String
val description: String
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
index 9d7b940..a3b23ca 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
@@ -2,7 +2,6 @@
import android.content.Context
import android.graphics.drawable.Drawable
-import android.os.UserHandle
import android.text.InputType
import com.android.internal.widget.LockPatternView
import com.android.systemui.R
@@ -10,6 +9,7 @@
import com.android.systemui.biometrics.domain.interactor.CredentialStatus
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.dagger.qualifiers.Application
import javax.inject.Inject
import kotlin.reflect.KClass
@@ -36,7 +36,7 @@
request ->
BiometricPromptHeaderViewModelImpl(
request,
- user = UserHandle.of(request.userInfo.userId),
+ user = request.userInfo,
title = request.title,
subtitle = request.subtitle,
description = request.description,
@@ -169,7 +169,7 @@
private class BiometricPromptHeaderViewModelImpl(
val request: BiometricPromptRequest.Credential,
- override val user: UserHandle,
+ override val user: BiometricUserInfo,
override val title: String,
override val subtitle: String,
override val description: String,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt
index 444082c..2f9557f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthState.kt
@@ -16,7 +16,7 @@
package com.android.systemui.biometrics.ui.viewmodel
-import com.android.systemui.biometrics.domain.model.BiometricModality
+import com.android.systemui.biometrics.shared.model.BiometricModality
/**
* The authenticated state with the [authenticatedModality] (when [isAuthenticated]) with an
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptMessage.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptMessage.kt
index 219da71..50f4911 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptMessage.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptMessage.kt
@@ -33,9 +33,9 @@
else -> ""
}
- /** If this is an [Error] or [Help] message. */
- val isErrorOrHelp: Boolean
- get() = this is Error || this is Help
+ /** If this is an [Error]. */
+ val isError: Boolean
+ get() = this is Error
/** An error message. */
data class Error(val errorMessage: String) : PromptMessage
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 05a5362..8a2e405 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -20,8 +20,9 @@
import com.android.systemui.biometrics.AuthBiometricView
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.model.BiometricModalities
-import com.android.systemui.biometrics.domain.model.BiometricModality
+import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.PromptKind
+import com.android.systemui.statusbar.VibratorHelper
import javax.inject.Inject
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
@@ -41,6 +42,7 @@
@Inject
constructor(
private val interactor: PromptSelectorInteractor,
+ private val vibrator: VibratorHelper,
) {
/** The set of modalities available for this prompt */
val modalities: Flow<BiometricModalities> =
@@ -205,37 +207,43 @@
private var messageJob: Job? = null
/**
- * Show a temporary error [message] associated with an optional [failedModality].
+ * Show a temporary error [message] associated with an optional [failedModality] and play
+ * [hapticFeedback].
*
- * An optional [messageAfterError] will be shown via [showAuthenticating] when
- * [authenticateAfterError] is set (or via [showHelp] when not set) after the error is
- * dismissed.
+ * The [messageAfterError] will be shown via [showAuthenticating] when [authenticateAfterError]
+ * is set (or via [showHelp] when not set) after the error is dismissed.
*
- * The error is ignored if the user has already authenticated and it is treated as
- * [onSilentError] if [suppressIfErrorShowing] is set and an error message is already showing.
+ * The error is ignored if the user has already authenticated or if [suppressIf] is true given
+ * the currently showing [PromptMessage].
*/
suspend fun showTemporaryError(
message: String,
- messageAfterError: String = "",
- authenticateAfterError: Boolean = false,
- suppressIfErrorShowing: Boolean = false,
+ messageAfterError: String,
+ authenticateAfterError: Boolean,
+ suppressIf: (PromptMessage) -> Boolean = { false },
+ hapticFeedback: Boolean = true,
failedModality: BiometricModality = BiometricModality.None,
) = coroutineScope {
if (_isAuthenticated.value.isAuthenticated) {
return@coroutineScope
}
- if (_message.value.isErrorOrHelp && suppressIfErrorShowing) {
- onSilentError(failedModality)
+
+ _canTryAgainNow.value = supportsRetry(failedModality)
+
+ if (suppressIf(_message.value)) {
return@coroutineScope
}
_isAuthenticating.value = false
_isAuthenticated.value = PromptAuthState(false)
_forceMediumSize.value = true
- _canTryAgainNow.value = supportsRetry(failedModality)
_message.value = PromptMessage.Error(message)
_legacyState.value = AuthBiometricView.STATE_ERROR
+ if (hapticFeedback) {
+ vibrator.error(failedModality)
+ }
+
messageJob?.cancel()
messageJob = launch {
delay(BiometricPrompt.HIDE_DIALOG_DELAY.toLong())
@@ -248,18 +256,6 @@
}
/**
- * Call instead of [showTemporaryError] if an error from the HAL should be silently ignored to
- * enable retry (if the [failedModality] supports retrying).
- *
- * Ignored if the user has already authenticated.
- */
- private fun onSilentError(failedModality: BiometricModality = BiometricModality.None) {
- if (_isAuthenticated.value.isNotAuthenticated) {
- _canTryAgainNow.value = supportsRetry(failedModality)
- }
- }
-
- /**
* Call to ensure the fingerprint sensor has started. Either when the dialog is first shown
* (most cases) or when it should be enabled after a first error (coex implicit flow).
*/
@@ -376,6 +372,10 @@
AuthBiometricView.STATE_AUTHENTICATED
}
+ if (!needsUserConfirmation) {
+ vibrator.success(modality)
+ }
+
messageJob?.cancel()
messageJob = null
@@ -386,18 +386,18 @@
private suspend fun needsExplicitConfirmation(modality: BiometricModality): Boolean {
val availableModalities = modalities.first()
- val confirmationRequested = interactor.isConfirmationRequired.first()
+ val confirmationRequired = isConfirmationRequired.first()
if (availableModalities.hasFaceAndFingerprint) {
// coex only needs confirmation when face is successful, unless it happens on the
// first attempt (i.e. without failure) before fingerprint scanning starts
+ val fingerprintStarted = fingerprintStartMode.first() != FingerprintStartMode.Pending
if (modality == BiometricModality.Face) {
- return (fingerprintStartMode.first() != FingerprintStartMode.Pending) ||
- confirmationRequested
+ return fingerprintStarted || confirmationRequired
}
}
if (availableModalities.hasFaceOnly) {
- return confirmationRequested
+ return confirmationRequired
}
// fingerprint only never requires confirmation
return false
@@ -412,7 +412,6 @@
fun confirmAuthenticated() {
val authState = _isAuthenticated.value
if (authState.isNotAuthenticated) {
- "Cannot show authenticated after authenticated"
Log.w(TAG, "Cannot confirm authenticated when not authenticated")
return
}
@@ -421,6 +420,8 @@
_message.value = PromptMessage.Empty
_legacyState.value = AuthBiometricView.STATE_AUTHENTICATED
+ vibrator.success(authState.authenticatedModality)
+
messageJob?.cancel()
messageJob = null
}
@@ -434,6 +435,12 @@
_forceLargeSize.value = true
}
+ private fun VibratorHelper.success(modality: BiometricModality) =
+ vibrateAuthSuccess("$TAG, modality = $modality BP::success")
+
+ private fun VibratorHelper.error(modality: BiometricModality = BiometricModality.None) =
+ vibrateAuthError("$TAG, modality = $modality BP::error")
+
companion object {
private const val TAG = "PromptViewModel"
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
index ff896fa..943216e 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt
@@ -16,7 +16,6 @@
package com.android.systemui.bouncer.data.repository
-import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
@@ -30,15 +29,7 @@
/** The user-facing message to show in the bouncer. */
val message: StateFlow<String?> = _message.asStateFlow()
- private val _throttling = MutableStateFlow<AuthenticationThrottledModel?>(null)
- /** The current authentication throttling state. If `null`, there's no throttling. */
- val throttling: StateFlow<AuthenticationThrottledModel?> = _throttling.asStateFlow()
-
fun setMessage(message: String?) {
_message.value = message
}
-
- fun setThrottling(throttling: AuthenticationThrottledModel?) {
- _throttling.value = throttling
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
index 5dd24b2..62a484d 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt
@@ -14,30 +14,32 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.bouncer.domain.interactor
import android.content.Context
-import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.bouncer.data.repository.BouncerRepository
-import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.util.kotlin.pairwise
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.delay
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -50,6 +52,7 @@
private val repository: BouncerRepository,
private val authenticationInteractor: AuthenticationInteractor,
private val sceneInteractor: SceneInteractor,
+ featureFlags: FeatureFlags,
@Assisted private val containerName: String,
) {
@@ -57,9 +60,10 @@
val message: StateFlow<String?> =
combine(
repository.message,
- repository.throttling,
- ) { message, throttling ->
- messageOrThrottlingMessage(message, throttling)
+ authenticationInteractor.isThrottled,
+ authenticationInteractor.throttling,
+ ) { message, isThrottled, throttling ->
+ messageOrThrottlingMessage(message, isThrottled, throttling)
}
.stateIn(
scope = applicationScope,
@@ -67,36 +71,39 @@
initialValue =
messageOrThrottlingMessage(
repository.message.value,
- repository.throttling.value,
+ authenticationInteractor.isThrottled.value,
+ authenticationInteractor.throttling.value,
)
)
- /** The current authentication throttling state. If `null`, there's no throttling. */
- val throttling: StateFlow<AuthenticationThrottledModel?> = repository.throttling
+ /** The current authentication throttling state, only meaningful if [isThrottled] is `true`. */
+ val throttling: StateFlow<AuthenticationThrottlingModel> = authenticationInteractor.throttling
+
+ /**
+ * Whether currently throttled and the user has to wait before being able to try another
+ * authentication attempt.
+ */
+ val isThrottled: StateFlow<Boolean> = authenticationInteractor.isThrottled
+
+ /** Whether the auto confirm feature is enabled for the currently-selected user. */
+ val isAutoConfirmEnabled: StateFlow<Boolean> = authenticationInteractor.isAutoConfirmEnabled
+
+ /** The length of the PIN for which we should show a hint. */
+ val hintedPinLength: StateFlow<Int?> = authenticationInteractor.hintedPinLength
+
+ /** Whether the pattern should be visible for the currently-selected user. */
+ val isPatternVisible: StateFlow<Boolean> = authenticationInteractor.isPatternVisible
init {
- // UNLOCKING SHOWS Gone.
- //
- // Move to the gone scene if the device becomes unlocked while on the bouncer scene.
- applicationScope.launch {
- sceneInteractor
- .currentScene(containerName)
- .flatMapLatest { currentScene ->
- if (currentScene.key == SceneKey.Bouncer) {
- authenticationInteractor.isUnlocked
- } else {
- flowOf(false)
+ if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ // Clear the message if moved from throttling to no-longer throttling.
+ applicationScope.launch {
+ isThrottled.pairwise().collect { (wasThrottled, currentlyThrottled) ->
+ if (wasThrottled && !currentlyThrottled) {
+ clearMessage()
}
}
- .distinctUntilChanged()
- .collect { isUnlocked ->
- if (isUnlocked) {
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Gone),
- )
- }
- }
+ }
}
}
@@ -168,41 +175,16 @@
input: List<Any>,
tryAutoConfirm: Boolean = false,
): Boolean? {
- if (repository.throttling.value != null) {
- return false
- }
-
val isAuthenticated =
authenticationInteractor.authenticate(input, tryAutoConfirm) ?: return null
- val failedAttempts = authenticationInteractor.failedAuthenticationAttempts.value
- when {
- isAuthenticated -> {
- repository.setThrottling(null)
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Gone),
- )
- }
- failedAttempts >= THROTTLE_AGGRESSIVELY_AFTER || failedAttempts % THROTTLE_EVERY == 0 ->
- applicationScope.launch {
- var remainingDurationSec = THROTTLE_DURATION_SEC
- while (remainingDurationSec > 0) {
- repository.setThrottling(
- AuthenticationThrottledModel(
- failedAttemptCount = failedAttempts,
- totalDurationSec = THROTTLE_DURATION_SEC,
- remainingDurationSec = remainingDurationSec,
- )
- )
- remainingDurationSec--
- delay(1000)
- }
-
- repository.setThrottling(null)
- clearMessage()
- }
- else -> repository.setMessage(errorMessage(getAuthenticationMethod()))
+ if (isAuthenticated) {
+ sceneInteractor.setCurrentScene(
+ containerName = containerName,
+ scene = SceneModel(SceneKey.Gone),
+ )
+ } else {
+ repository.setMessage(errorMessage(getAuthenticationMethod()))
}
return isAuthenticated
@@ -233,13 +215,14 @@
private fun messageOrThrottlingMessage(
message: String?,
- throttling: AuthenticationThrottledModel?,
+ isThrottled: Boolean,
+ throttlingModel: AuthenticationThrottlingModel,
): String {
return when {
- throttling != null ->
+ isThrottled ->
applicationContext.getString(
com.android.internal.R.string.lockscreen_too_many_failed_attempts_countdown,
- throttling.remainingDurationSec,
+ throttlingModel.remainingMs.milliseconds.inWholeSeconds,
)
message != null -> message
else -> ""
@@ -252,10 +235,4 @@
containerName: String,
): BouncerInteractor
}
-
- companion object {
- @VisibleForTesting const val THROTTLE_DURATION_SEC = 30
- @VisibleForTesting const val THROTTLE_AGGRESSIVELY_AFTER = 15
- @VisibleForTesting const val THROTTLE_EVERY = 5
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/AuthenticationThrottledModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/AuthenticationThrottledModel.kt
deleted file mode 100644
index cbea635..0000000
--- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/AuthenticationThrottledModel.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.bouncer.shared.model
-
-/**
- * Models application state for when further authentication attempts are being throttled due to too
- * many consecutive failed authentication attempts.
- */
-data class AuthenticationThrottledModel(
- /** Total number of failed attempts so far. */
- val failedAttemptCount: Int,
- /** Total amount of time the user has to wait before attempting again. */
- val totalDurationSec: Int,
- /** Remaining amount of time the user has to wait before attempting again. */
- val remainingDurationSec: Int,
-)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index db6ca0b..a4ef5ce 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -14,19 +14,24 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
package com.android.systemui.bouncer.ui.viewmodel
import android.content.Context
import com.android.systemui.R
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
-import com.android.systemui.bouncer.shared.model.AuthenticationThrottledModel
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.util.kotlin.pairwise
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlin.math.ceil
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -46,17 +51,18 @@
@Application private val applicationContext: Context,
@Application private val applicationScope: CoroutineScope,
interactorFactory: BouncerInteractor.Factory,
+ featureFlags: FeatureFlags,
@Assisted containerName: String,
) {
private val interactor: BouncerInteractor = interactorFactory.create(containerName)
private val isInputEnabled: StateFlow<Boolean> =
- interactor.throttling
- .map { it == null }
+ interactor.isThrottled
+ .map { !it }
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = interactor.throttling.value == null,
+ initialValue = !interactor.isThrottled.value,
)
private val pin: PinBouncerViewModel by lazy {
@@ -99,15 +105,48 @@
)
init {
- applicationScope.launch {
- _authMethod.subscriptionCount
- .pairwise()
- .map { (previousCount, currentCount) -> currentCount > previousCount }
- .collect { subscriberAdded ->
- if (subscriberAdded) {
- reloadAuthMethod()
+ if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ applicationScope.launch {
+ interactor.isThrottled
+ .map { isThrottled ->
+ if (isThrottled) {
+ when (interactor.getAuthenticationMethod()) {
+ is AuthenticationMethodModel.Pin ->
+ R.string.kg_too_many_failed_pin_attempts_dialog_message
+ is AuthenticationMethodModel.Password ->
+ R.string.kg_too_many_failed_password_attempts_dialog_message
+ is AuthenticationMethodModel.Pattern ->
+ R.string.kg_too_many_failed_pattern_attempts_dialog_message
+ else -> null
+ }?.let { stringResourceId ->
+ applicationContext.getString(
+ stringResourceId,
+ interactor.throttling.value.failedAttemptCount,
+ ceil(interactor.throttling.value.remainingMs / 1000f).toInt(),
+ )
+ }
+ } else {
+ null
+ }
}
- }
+ .distinctUntilChanged()
+ .collect { dialogMessageOrNull ->
+ if (dialogMessageOrNull != null) {
+ _throttlingDialogMessage.value = dialogMessageOrNull
+ }
+ }
+ }
+
+ applicationScope.launch {
+ _authMethod.subscriptionCount
+ .pairwise()
+ .map { (previousCount, currentCount) -> currentCount > previousCount }
+ .collect { subscriberAdded ->
+ if (subscriberAdded) {
+ reloadAuthMethod()
+ }
+ }
+ }
}
}
@@ -115,9 +154,9 @@
val message: StateFlow<MessageViewModel> =
combine(
interactor.message,
- interactor.throttling,
- ) { message, throttling ->
- toMessageViewModel(message, throttling)
+ interactor.isThrottled,
+ ) { message, isThrottled ->
+ toMessageViewModel(message, isThrottled)
}
.stateIn(
scope = applicationScope,
@@ -125,7 +164,7 @@
initialValue =
toMessageViewModel(
message = interactor.message.value,
- throttling = interactor.throttling.value,
+ isThrottled = interactor.isThrottled.value,
),
)
@@ -141,37 +180,6 @@
*/
val throttlingDialogMessage: StateFlow<String?> = _throttlingDialogMessage.asStateFlow()
- init {
- applicationScope.launch {
- interactor.throttling
- .map { model ->
- model?.let {
- when (interactor.getAuthenticationMethod()) {
- is AuthenticationMethodModel.Pin ->
- R.string.kg_too_many_failed_pin_attempts_dialog_message
- is AuthenticationMethodModel.Password ->
- R.string.kg_too_many_failed_password_attempts_dialog_message
- is AuthenticationMethodModel.Pattern ->
- R.string.kg_too_many_failed_pattern_attempts_dialog_message
- else -> null
- }?.let { stringResourceId ->
- applicationContext.getString(
- stringResourceId,
- model.failedAttemptCount,
- model.totalDurationSec,
- )
- }
- }
- }
- .distinctUntilChanged()
- .collect { dialogMessageOrNull ->
- if (dialogMessageOrNull != null) {
- _throttlingDialogMessage.value = dialogMessageOrNull
- }
- }
- }
- }
-
/** Notifies that the emergency services button was clicked. */
fun onEmergencyServicesButtonClicked() {
// TODO(b/280877228): implement this
@@ -184,11 +192,11 @@
private fun toMessageViewModel(
message: String?,
- throttling: AuthenticationThrottledModel?,
+ isThrottled: Boolean,
): MessageViewModel {
return MessageViewModel(
text = message ?: "",
- isUpdateAnimated = throttling == null,
+ isUpdateAnimated = !isThrottled,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
index 5efa6f0..4be539d 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModel.kt
@@ -29,7 +29,6 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -70,19 +69,7 @@
val dots: StateFlow<List<PatternDotViewModel>> = _dots.asStateFlow()
/** Whether the pattern itself should be rendered visibly. */
- val isPatternVisible: StateFlow<Boolean> =
- flow {
- emit(null)
- emit(interactor.getAuthenticationMethod())
- }
- .map { authMethod ->
- (authMethod as? AuthenticationMethodModel.Pattern)?.isPatternVisible ?: false
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = false,
- )
+ val isPatternVisible: StateFlow<Boolean> = interactor.isPatternVisible
/** Notifies that the UI has been shown to the user. */
fun onShown() {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
index 641e863..1b14acc 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModel.kt
@@ -18,13 +18,12 @@
import android.content.Context
import com.android.keyguard.PinShapeAdapter
-import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -45,26 +44,18 @@
private val mutablePinEntries = MutableStateFlow<List<EnteredKey>>(emptyList())
val pinEntries: StateFlow<List<EnteredKey>> = mutablePinEntries
- /** The length of the hinted PIN, or `null` if pin length hint should not be shown. */
- val hintedPinLength: StateFlow<Int?> =
- flow { emit(interactor.getAuthenticationMethod()) }
- .map { authMethod ->
- // Hinting is enabled for 6-digit codes only
- autoConfirmPinLength(authMethod).takeIf { it == HINTING_PASSCODE_LENGTH }
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = null,
- )
+ /** The length of the PIN for which we should show a hint. */
+ val hintedPinLength: StateFlow<Int?> = interactor.hintedPinLength
/** Appearance of the backspace button. */
val backspaceButtonAppearance: StateFlow<ActionButtonAppearance> =
- mutablePinEntries
- .map { mutablePinEntries ->
+ combine(
+ mutablePinEntries,
+ interactor.isAutoConfirmEnabled,
+ ) { mutablePinEntries, isAutoConfirmEnabled ->
computeBackspaceButtonAppearance(
- interactor.getAuthenticationMethod(),
- mutablePinEntries
+ enteredPin = mutablePinEntries,
+ isAutoConfirmEnabled = isAutoConfirmEnabled,
)
}
.stateIn(
@@ -75,11 +66,14 @@
/** Appearance of the confirm button. */
val confirmButtonAppearance: StateFlow<ActionButtonAppearance> =
- flow {
- emit(null)
- emit(interactor.getAuthenticationMethod())
+ interactor.isAutoConfirmEnabled
+ .map {
+ if (it) {
+ ActionButtonAppearance.Hidden
+ } else {
+ ActionButtonAppearance.Shown
+ }
}
- .map { authMethod -> computeConfirmButtonAppearance(authMethod) }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
@@ -134,21 +128,10 @@
}
}
- private fun isAutoConfirmEnabled(authMethodModel: AuthenticationMethodModel?): Boolean {
- return (authMethodModel as? AuthenticationMethodModel.Pin)?.autoConfirm == true
- }
-
- private fun autoConfirmPinLength(authMethodModel: AuthenticationMethodModel?): Int? {
- if (!isAutoConfirmEnabled(authMethodModel)) return null
-
- return (authMethodModel as? AuthenticationMethodModel.Pin)?.code?.size
- }
-
private fun computeBackspaceButtonAppearance(
- authMethodModel: AuthenticationMethodModel,
- enteredPin: List<EnteredKey>
+ enteredPin: List<EnteredKey>,
+ isAutoConfirmEnabled: Boolean,
): ActionButtonAppearance {
- val isAutoConfirmEnabled = isAutoConfirmEnabled(authMethodModel)
val isEmpty = enteredPin.isEmpty()
return when {
@@ -157,15 +140,6 @@
else -> ActionButtonAppearance.Shown
}
}
- private fun computeConfirmButtonAppearance(
- authMethodModel: AuthenticationMethodModel?
- ): ActionButtonAppearance {
- return if (isAutoConfirmEnabled(authMethodModel)) {
- ActionButtonAppearance.Hidden
- } else {
- ActionButtonAppearance.Shown
- }
- }
}
/** Appearance of pin-pad action buttons. */
@@ -178,9 +152,6 @@
Shown,
}
-/** Auto-confirm passcodes of exactly 6 digits show a length hint, see http://shortn/_IXlmSNbDh6 */
-private const val HINTING_PASSCODE_LENGTH = 6
-
private var nextSequenceNumber = 1
/**
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
index 277b427..f362831 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/SeekBarWithIconButtonsView.java
@@ -171,6 +171,22 @@
}
/**
+ * Only for testing. Get previous set mOnSeekBarChangeListener to the seekbar.
+ */
+ @VisibleForTesting
+ public OnSeekBarWithIconButtonsChangeListener getOnSeekBarWithIconButtonsChangeListener() {
+ return mSeekBarListener.mOnSeekBarChangeListener;
+ }
+
+ /**
+ * Only for testing. Get {@link #mSeekbar} in the layout.
+ */
+ @VisibleForTesting
+ public SeekBar getSeekbar() {
+ return mSeekbar;
+ }
+
+ /**
* Start and End icons might need to be updated when there is a change in seekbar progress.
* Icon Start will need to be enabled when the seekbar progress is larger than 0.
* Icon End will need to be enabled when the seekbar progress is less than Max.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt
index 1973b62..840225e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt
@@ -52,7 +52,7 @@
/** Start monitoring for package updates. No-op if already monitoring. */
fun startMonitoring() {
if (monitoring.compareAndSet(/* expected */ false, /* new */ true)) {
- register(context, user, false, bgHandler)
+ register(context, user, bgHandler)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
index ce0f2e9..501bcf0 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/settings/ControlsSettingsDialogManager.kt
@@ -135,7 +135,7 @@
val listener = DialogListener(prefs, attempts, onAttemptCompleted)
val d =
dialogProvider(activityContext, R.style.Theme_SystemUI_Dialog).apply {
- setIcon(R.drawable.ic_warning)
+ setIcon(R.drawable.ic_lock_locked)
setOnCancelListener(listener)
setNeutralButton(R.string.controls_settings_dialog_neutral_button, listener)
setPositiveButton(R.string.controls_settings_dialog_positive_button, listener)
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 7be9424..64d4583 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -279,7 +279,7 @@
controlsListingController.get().removeCallback(listingCallback)
controlsController.get().unsubscribe()
- taskViewController?.dismiss()
+ taskViewController?.removeTask()
taskViewController = null
val fadeAnim = ObjectAnimator.ofFloat(parent, "alpha", 1.0f, 0.0f)
@@ -777,7 +777,7 @@
closeDialogs(true)
controlsController.get().unsubscribe()
- taskViewController?.dismiss()
+ taskViewController?.removeTask()
taskViewController = null
controlsById.clear()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
index 025d7e4..db009dc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/PanelTaskViewController.kt
@@ -18,7 +18,6 @@
package com.android.systemui.controls.ui
import android.app.ActivityOptions
-import android.app.ActivityTaskManager
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.app.PendingIntent
import android.content.ComponentName
@@ -28,6 +27,7 @@
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.os.Trace
+import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.util.boundsOnScreen
import com.android.wm.shell.taskview.TaskView
@@ -54,12 +54,6 @@
addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
}
- private fun removeDetailTask() {
- if (detailTaskId == INVALID_TASK_ID) return
- ActivityTaskManager.getInstance().removeTask(detailTaskId)
- detailTaskId = INVALID_TASK_ID
- }
-
private val stateCallback =
object : TaskView.Listener {
override fun onInitialized() {
@@ -95,7 +89,7 @@
override fun onTaskRemovalStarted(taskId: Int) {
detailTaskId = INVALID_TASK_ID
- dismiss()
+ release()
}
override fun onTaskCreated(taskId: Int, name: ComponentName?) {
@@ -103,12 +97,7 @@
taskView.alpha = 1f
}
- override fun onReleased() {
- removeDetailTask()
- }
-
override fun onBackPressedOnTaskRoot(taskId: Int) {
- dismiss()
hide()
}
}
@@ -117,10 +106,17 @@
taskView.onLocationChanged()
}
- fun dismiss() {
+ /** Call when the taskView is no longer being used, shouldn't be called before removeTask. */
+ @VisibleForTesting
+ fun release() {
taskView.release()
}
+ /** Call to explicitly remove the task from window manager. */
+ fun removeTask() {
+ taskView.removeTask()
+ }
+
fun launchTaskView() {
taskView.setListener(uiExecutor, stateCallback)
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index 5493cea..94b2ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -19,6 +19,7 @@
import com.android.systemui.globalactions.ShutdownUiModule;
import com.android.systemui.keyguard.CustomizationProvider;
import com.android.systemui.scene.startable.SceneContainerStartableModule;
+import com.android.systemui.shade.ShadeModule;
import com.android.systemui.statusbar.NotificationInsetsModule;
import com.android.systemui.statusbar.QsFrameTranslateModule;
@@ -33,6 +34,7 @@
DependencyProvider.class,
NotificationInsetsModule.class,
QsFrameTranslateModule.class,
+ ShadeModule.class,
ShutdownUiModule.class,
SceneContainerStartableModule.class,
SystemUIBinder.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index eef8508..18b5612 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -81,7 +81,6 @@
import com.android.systemui.security.data.repository.SecurityRepositoryModule;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.ShadeModule;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolatorImpl;
import com.android.systemui.shared.condition.Monitor;
@@ -198,7 +197,6 @@
SecurityRepositoryModule.class,
ScreenRecordModule.class,
SettingsUtilModule.class,
- ShadeModule.class,
SmartRepliesInflationModule.class,
SmartspaceModule.class,
StatusBarPipelineModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 68211ee..a5a7995 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -91,6 +91,11 @@
val NOTIFICATION_SHELF_REFACTOR =
unreleasedFlag(271161129, "notification_shelf_refactor", teamfood = true)
+ // TODO(b/290787599): Tracking Bug
+ @JvmField
+ val NOTIFICATION_ICON_CONTAINER_REFACTOR =
+ unreleasedFlag(278765923, "notification_icon_container_refactor")
+
// TODO(b/288326013): Tracking Bug
@JvmField
val NOTIFICATION_ASYNC_HYBRID_VIEW_INFLATION =
@@ -146,6 +151,14 @@
val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = releasedFlag(208,
"lockscreen_without_secure_lock_when_dreaming")
+ // TODO(b/286092087): Tracking Bug
+ @JvmField
+ val ENABLE_SYSTEM_UI_DREAM_CONTROLLER = unreleasedFlag(301, "enable_system_ui_dream_controller")
+
+ // TODO(b/288287730): Tracking Bug
+ @JvmField
+ val ENABLE_SYSTEM_UI_DREAM_HOSTING = unreleasedFlag(302, "enable_system_ui_dream_hosting")
+
/**
* Whether the clock on a wide lock screen should use the new "stepping" animation for moving
* the digits when the clock moves.
@@ -161,16 +174,6 @@
@JvmField val DOZING_MIGRATION_1 = unreleasedFlag(213, "dozing_migration_1")
/**
- * Whether to enable the code powering customizable lock screen quick affordances.
- *
- * This flag enables any new prebuilt quick affordances as well.
- */
- // TODO(b/255618149): Tracking Bug
- @JvmField
- val CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES =
- releasedFlag(216, "customizable_lock_screen_quick_affordances")
-
- /**
* Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the
* new KeyguardTransitionRepository.
*/
@@ -260,6 +263,16 @@
@JvmField
val MIGRATE_INDICATION_AREA = unreleasedFlag(236, "migrate_indication_area", teamfood = true)
+ /**
+ * Migrate the bottom area to the new keyguard root view.
+ * Because there is no such thing as a "bottom area" after this, this also breaks it up into
+ * many smaller, modular pieces.
+ */
+ // TODO(b/290652751): Tracking bug.
+ @JvmField
+ val MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA =
+ unreleasedFlag(290652751, "migrate_split_keyguard_bottom_area")
+
/** Whether to listen for fingerprint authentication over keyguard occluding activities. */
// TODO(b/283260512): Tracking bug.
@JvmField
@@ -279,6 +292,10 @@
@JvmField
val MIGRATE_LOCK_ICON = unreleasedFlag(240, "migrate_lock_icon")
+ // TODO(b/288276738): Tracking bug.
+ @JvmField
+ val WIDGET_ON_KEYGUARD = unreleasedFlag(241, "widget_on_keyguard")
+
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -429,9 +446,6 @@
// TODO(b/263272731): Tracking Bug
val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag(910, "media_ttt_receiver_success_ripple")
- // TODO(b/263512203): Tracking Bug
- val MEDIA_EXPLICIT_INDICATOR = releasedFlag(911, "media_explicit_indicator")
-
// TODO(b/265813373): Tracking Bug
val MEDIA_TAP_TO_TRANSFER_DISMISS_GESTURE = releasedFlag(912, "media_ttt_dismiss_gesture")
@@ -559,6 +573,12 @@
val WALLPAPER_MULTI_CROP =
sysPropBooleanFlag(1118, "persist.wm.debug.wallpaper_multi_crop", default = false)
+ // TODO(b/290220798): Tracking Bug
+ @Keep
+ @JvmField
+ val ENABLE_PIP2_IMPLEMENTATION =
+ sysPropBooleanFlag(1119, "persist.wm.debug.enable_pip2_implementation", default = false)
+
// 1200 - predictive back
@Keep
@@ -693,11 +713,11 @@
// TODO(b/283071711): Tracking bug
@JvmField
val TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK =
- releasedFlag(2401, "trim_resources_with_background_trim_on_lock")
+ unreleasedFlag(2401, "trim_resources_with_background_trim_on_lock")
// TODO:(b/283203305): Tracking bug
@JvmField
- val TRIM_FONT_CACHES_AT_UNLOCK = releasedFlag(2402, "trim_font_caches_on_unlock")
+ val TRIM_FONT_CACHES_AT_UNLOCK = unreleasedFlag(2402, "trim_font_caches_on_unlock")
// 2700 - unfold transitions
// TODO(b/265764985): Tracking Bug
@@ -769,6 +789,11 @@
val ENABLE_NEW_PRIVACY_DIALOG =
unreleasedFlag(283740863, "enable_new_privacy_dialog", teamfood = false)
+ // TODO(b/289573946): Tracking Bug
+ @JvmField
+ val PRECOMPUTED_TEXT =
+ unreleasedFlag(289573946, "precomputed_text")
+
// 2900 - CentralSurfaces-related flags
// TODO(b/285174336): Tracking Bug
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 0511314..732102e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -50,6 +50,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.SystemUIAppComponentFactoryBase;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -151,6 +152,9 @@
private SystemUIAppComponentFactoryBase.ContextAvailableCallback mContextAvailableCallback;
@Inject
WakeLockLogger mWakeLockLogger;
+ @Inject
+ @Background
+ Handler mBgHandler;
/**
* Receiver responsible for time ticking and updating the date format.
@@ -502,7 +506,7 @@
}
protected void notifyChange() {
- mContentResolver.notifyChange(mSliceUri, null /* observer */);
+ mBgHandler.post(() -> mContentResolver.notifyChange(mSliceUri, null /* observer */));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index ced41aa..1487408 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -51,7 +51,6 @@
import com.android.systemui.keyguard.data.repository.KeyguardFaceAuthModule;
import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
-import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
@@ -92,7 +91,6 @@
includes = {
FalsingModule.class,
KeyguardDataQuickAffordanceModule.class,
- KeyguardQuickAffordanceModule.class,
KeyguardRepositoryModule.class,
KeyguardFaceAuthModule.class,
StartKeyguardTransitionModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartable.kt
index cd0805e..7dbe945 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartable.kt
@@ -24,8 +24,6 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
@@ -42,7 +40,6 @@
*/
@SysUISingleton
class MuteQuickAffordanceCoreStartable @Inject constructor(
- private val featureFlags: FeatureFlags,
private val userTracker: UserTracker,
private val ringerModeTracker: RingerModeTracker,
private val userFileManager: UserFileManager,
@@ -54,8 +51,6 @@
private val observer = Observer(this::updateLastNonSilentRingerMode)
override fun start() {
- if (!featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)) return
-
// only listen to ringerModeInternal changes when Mute is one of the selected affordances
keyguardQuickAffordanceRepository
.selections
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 3d8f6fd..a3d1abe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -31,6 +31,7 @@
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
@@ -126,6 +127,7 @@
private val keyguardBypassController: KeyguardBypassController? = null,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
private val sessionTracker: SessionTracker,
private val uiEventsLogger: UiEventLogger,
private val faceAuthLogger: FaceAuthenticationLogger,
@@ -228,8 +230,12 @@
keyguardTransitionInteractor.anyStateToGoneTransition
.filter { it.transitionState == TransitionState.FINISHED }
.onEach {
- faceAuthLogger.watchdogScheduled()
- faceManager?.scheduleWatchdog()
+ // We deliberately want to run this in background because scheduleWatchdog does
+ // a Binder IPC.
+ withContext(backgroundDispatcher) {
+ faceAuthLogger.watchdogScheduled()
+ faceManager?.scheduleWatchdog()
+ }
}
.launchIn(applicationScope)
}
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 edc0b45..e7704d6 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
@@ -121,6 +121,9 @@
/** Observable for whether the device is dreaming with an overlay, see [DreamOverlayService] */
val isDreamingWithOverlay: Flow<Boolean>
+ /** Observable for device dreaming state and the active dream is hosted in lockscreen */
+ val isActiveDreamLockscreenHosted: StateFlow<Boolean>
+
/**
* Observable for the amount of doze we are currently in.
*
@@ -190,6 +193,8 @@
fun setLastDozeTapToWakePosition(position: Point)
fun setIsDozing(isDozing: Boolean)
+
+ fun setIsActiveDreamLockscreenHosted(isLockscreenHosted: Boolean)
}
/** Encapsulates application state for the keyguard. */
@@ -610,6 +615,9 @@
private val _isQuickSettingsVisible = MutableStateFlow(false)
override val isQuickSettingsVisible: Flow<Boolean> = _isQuickSettingsVisible.asStateFlow()
+ private val _isActiveDreamLockscreenHosted = MutableStateFlow(false)
+ override val isActiveDreamLockscreenHosted = _isActiveDreamLockscreenHosted.asStateFlow()
+
override fun setAnimateDozingTransitions(animate: Boolean) {
_animateBottomAreaDozingTransitions.value = animate
}
@@ -628,6 +636,10 @@
_isQuickSettingsVisible.value = isVisible
}
+ override fun setIsActiveDreamLockscreenHosted(isLockscreenHosted: Boolean) {
+ _isActiveDreamLockscreenHosted.value = isLockscreenHosted
+ }
+
private fun statusBarStateIntToObject(value: Int): StatusBarState {
return when (value) {
0 -> StatusBarState.SHADE
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 228290a..7fae752 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
@@ -81,6 +81,8 @@
val isDreaming: Flow<Boolean> = repository.isDreaming
/** Whether the system is dreaming with an overlay active */
val isDreamingWithOverlay: Flow<Boolean> = repository.isDreamingWithOverlay
+ /** Whether the system is dreaming and the active dream is hosted in lockscreen */
+ val isActiveDreamLockscreenHosted: Flow<Boolean> = repository.isActiveDreamLockscreenHosted
/** Event for when the camera gesture is detected */
val onCameraLaunchDetected: Flow<CameraLaunchSourceModel> = conflatedCallbackFlow {
val callback =
@@ -198,6 +200,10 @@
}
}
+ fun setIsActiveDreamLockscreenHosted(isLockscreenHosted: Boolean) {
+ repository.setIsActiveDreamLockscreenHosted(isLockscreenHosted)
+ }
+
/** Sets whether quick settings or quick-quick settings is visible. */
fun setQuickSettingsVisible(isVisible: Boolean) {
repository.setQuickSettingsVisible(isVisible)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index f692a39..324d443 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -38,7 +38,6 @@
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.shared.model.KeyguardPickerFlag
import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation
import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
@@ -68,7 +67,6 @@
@Inject
constructor(
private val keyguardInteractor: KeyguardInteractor,
- private val registry: KeyguardQuickAffordanceRegistry<out KeyguardQuickAffordanceConfig>,
private val lockPatternUtils: LockPatternUtils,
private val keyguardStateController: KeyguardStateController,
private val userTracker: UserTracker,
@@ -83,20 +81,13 @@
@Background private val backgroundDispatcher: CoroutineDispatcher,
@Application private val appContext: Context,
) {
- private val isUsingRepository: Boolean
- get() = featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)
/**
* Whether the UI should use the long press gesture to activate quick affordances.
*
* If `false`, the UI goes back to using single taps.
*/
- fun useLongPress(): Flow<Boolean> =
- if (featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)) {
- dockManager.retrieveIsDocked().map { !it }
- } else {
- flowOf(false)
- }
+ fun useLongPress(): Flow<Boolean> = dockManager.retrieveIsDocked().map { !it }
/** Returns an observable for the quick affordance at the given position. */
suspend fun quickAffordance(
@@ -147,14 +138,9 @@
expandable: Expandable?,
slotId: String,
) {
- @Suppress("UNCHECKED_CAST")
+ val (decodedSlotId, decodedConfigKey) = configKey.decode()
val config =
- if (isUsingRepository) {
- val (slotId, decodedConfigKey) = configKey.decode()
- repository.get().selections.value[slotId]?.find { it.key == decodedConfigKey }
- } else {
- registry.get(configKey)
- }
+ repository.get().selections.value[decodedSlotId]?.find { it.key == decodedConfigKey }
if (config == null) {
Log.e(TAG, "Affordance config with key of \"$configKey\" not found!")
return
@@ -183,7 +169,6 @@
* @return `true` if the affordance was selected successfully; `false` otherwise.
*/
suspend fun select(slotId: String, affordanceId: String): Boolean {
- check(isUsingRepository)
if (isFeatureDisabledByDevicePolicy()) {
return false
}
@@ -226,7 +211,6 @@
* the affordance was not on the slot to begin with).
*/
suspend fun unselect(slotId: String, affordanceId: String?): Boolean {
- check(isUsingRepository)
if (isFeatureDisabledByDevicePolicy()) {
return false
}
@@ -286,17 +270,12 @@
private fun quickAffordanceInternal(
position: KeyguardQuickAffordancePosition
- ): Flow<KeyguardQuickAffordanceModel> {
- return if (isUsingRepository) {
- repository
- .get()
- .selections
- .map { it[position.toSlotId()] ?: emptyList() }
- .flatMapLatest { configs -> combinedConfigs(position, configs) }
- } else {
- combinedConfigs(position, registry.getAll(position))
- }
- }
+ ): Flow<KeyguardQuickAffordanceModel> =
+ repository
+ .get()
+ .selections
+ .map { it[position.toSlotId()] ?: emptyList() }
+ .flatMapLatest { configs -> combinedConfigs(position, configs) }
private fun combinedConfigs(
position: KeyguardQuickAffordancePosition,
@@ -326,12 +305,7 @@
states[index] as KeyguardQuickAffordanceConfig.LockScreenState.Visible
val configKey = configs[index].key
KeyguardQuickAffordanceModel.Visible(
- configKey =
- if (isUsingRepository) {
- configKey.encode(position.toSlotId())
- } else {
- configKey
- },
+ configKey = configKey.encode(position.toSlotId()),
icon = visibleState.icon,
activationState = visibleState.activationState,
)
@@ -397,8 +371,6 @@
}
suspend fun getSlotPickerRepresentations(): List<KeyguardSlotPickerRepresentation> {
- check(isUsingRepository)
-
if (isFeatureDisabledByDevicePolicy()) {
return emptyList()
}
@@ -416,7 +388,6 @@
name = Contract.FlagsTable.FLAG_NAME_CUSTOM_LOCK_SCREEN_QUICK_AFFORDANCES_ENABLED,
value =
!isFeatureDisabledByDevicePolicy() &&
- featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES) &&
appContext.resources.getBoolean(R.bool.custom_lockscreen_shortcuts_enabled),
),
KeyguardPickerFlag(
@@ -443,7 +414,7 @@
}
private suspend fun isFeatureDisabledByDevicePolicy(): Boolean =
- traceAsync("isFeatureDisabledByDevicePolicy", TAG) {
+ traceAsync(TAG, "isFeatureDisabledByDevicePolicy") {
withContext(backgroundDispatcher) {
devicePolicyManager.areKeyguardShortcutsDisabled(userId = userTracker.userId)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
index c8f7efb..1c200b0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractor.kt
@@ -20,20 +20,14 @@
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.scene.shared.model.SceneModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
/** Hosts business and application state accessing logic for the lockscreen scene. */
class LockscreenSceneInteractor
@@ -42,7 +36,6 @@
@Application applicationScope: CoroutineScope,
private val authenticationInteractor: AuthenticationInteractor,
bouncerInteractorFactory: BouncerInteractor.Factory,
- private val sceneInteractor: SceneInteractor,
@Assisted private val containerName: String,
) {
private val bouncerInteractor: BouncerInteractor =
@@ -72,46 +65,6 @@
initialValue = false,
)
- init {
- // LOCKING SHOWS Lockscreen.
- //
- // Move to the lockscreen scene if the device becomes locked while in any scene.
- applicationScope.launch {
- authenticationInteractor.isUnlocked
- .map { !it }
- .distinctUntilChanged()
- .collect { isLocked ->
- if (isLocked) {
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Lockscreen),
- )
- }
- }
- }
-
- // BYPASS UNLOCK.
- //
- // Moves to the gone scene if bypass is enabled and the device becomes unlocked while in the
- // lockscreen scene.
- applicationScope.launch {
- combine(
- authenticationInteractor.isBypassEnabled,
- authenticationInteractor.isUnlocked,
- sceneInteractor.currentScene(containerName),
- ::Triple,
- )
- .collect { (isBypassEnabled, isUnlocked, currentScene) ->
- if (isBypassEnabled && isUnlocked && currentScene.key == SceneKey.Lockscreen) {
- sceneInteractor.setCurrentScene(
- containerName = containerName,
- scene = SceneModel(SceneKey.Gone),
- )
- }
- }
- }
- }
-
/** Attempts to dismiss the lockscreen. This will cause the bouncer to show, if needed. */
fun dismissLockscreen() {
bouncerInteractor.showOrUnlockDevice(containerName = containerName)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceModule.kt
deleted file mode 100644
index b48acb6..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceModule.kt
+++ /dev/null
@@ -1,30 +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.keyguard.domain.quickaffordance
-
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import dagger.Binds
-import dagger.Module
-
-@Module
-interface KeyguardQuickAffordanceModule {
- @Binds
- fun keyguardQuickAffordanceRegistry(
- impl: KeyguardQuickAffordanceRegistryImpl
- ): KeyguardQuickAffordanceRegistry<out KeyguardQuickAffordanceConfig>
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceRegistry.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceRegistry.kt
deleted file mode 100644
index 8526ada..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceRegistry.kt
+++ /dev/null
@@ -1,66 +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.keyguard.domain.quickaffordance
-
-import com.android.systemui.keyguard.data.quickaffordance.HomeControlsKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.QrCodeScannerKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.data.quickaffordance.QuickAccessWalletKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
-import javax.inject.Inject
-
-/** Central registry of all known quick affordance configs. */
-interface KeyguardQuickAffordanceRegistry<T : KeyguardQuickAffordanceConfig> {
- fun getAll(position: KeyguardQuickAffordancePosition): List<T>
- fun get(key: String): T
-}
-
-class KeyguardQuickAffordanceRegistryImpl
-@Inject
-constructor(
- homeControls: HomeControlsKeyguardQuickAffordanceConfig,
- quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
- qrCodeScanner: QrCodeScannerKeyguardQuickAffordanceConfig,
-) : KeyguardQuickAffordanceRegistry<KeyguardQuickAffordanceConfig> {
- private val configsByPosition =
- mapOf(
- KeyguardQuickAffordancePosition.BOTTOM_START to
- listOf(
- homeControls,
- ),
- KeyguardQuickAffordancePosition.BOTTOM_END to
- listOf(
- quickAccessWallet,
- qrCodeScanner,
- ),
- )
- private val configByKey =
- configsByPosition.values.flatten().associateBy { config -> config.key }
-
- override fun getAll(
- position: KeyguardQuickAffordancePosition,
- ): List<KeyguardQuickAffordanceConfig> {
- return configsByPosition.getValue(position)
- }
-
- override fun get(
- key: String,
- ): KeyguardQuickAffordanceConfig {
- return configByKey.getValue(key)
- }
-}
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 7d14198..db84268 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
@@ -343,9 +343,9 @@
Utils.getColorAttrDefaultColor(
view.context,
if (viewModel.isActivated) {
- com.android.internal.R.attr.textColorPrimaryInverse
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
} else {
- com.android.internal.R.attr.textColorPrimary
+ com.android.internal.R.attr.materialColorOnSurface
},
)
)
@@ -355,9 +355,9 @@
Utils.getColorAttr(
view.context,
if (viewModel.isActivated) {
- com.android.internal.R.attr.colorAccentPrimary
+ com.android.internal.R.attr.materialColorPrimaryFixed
} else {
- com.android.internal.R.attr.colorSurface
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh
}
)
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 4f4b58f..55dcd88 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -716,8 +716,7 @@
val appUid = currentEntry?.appUid ?: Process.INVALID_UID
val isExplicit =
desc.extras?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT &&
- mediaFlags.isExplicitIndicatorEnabled()
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
val progress =
if (mediaFlags.isResumeProgressEnabled()) {
@@ -826,12 +825,10 @@
// Explicit Indicator
var isExplicit = false
- if (mediaFlags.isExplicitIndicatorEnabled()) {
- val mediaMetadataCompat = MediaMetadataCompat.fromMediaMetadata(metadata)
- isExplicit =
- mediaMetadataCompat?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
- MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
- }
+ val mediaMetadataCompat = MediaMetadataCompat.fromMediaMetadata(metadata)
+ isExplicit =
+ mediaMetadataCompat?.getLong(MediaConstants.METADATA_KEY_IS_EXPLICIT) ==
+ MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT
// Artist name
var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
@@ -1253,6 +1250,9 @@
return try {
val options = BroadcastOptions.makeBasic()
options.setInteractive(true)
+ options.setPendingIntentBackgroundActivityStartMode(
+ BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ )
intent.send(options.toBundle())
true
} catch (e: PendingIntent.CanceledException) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 35082fd..a978b92 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -23,6 +23,7 @@
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
+import android.app.ActivityOptions;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
import android.app.WallpaperColors;
@@ -535,7 +536,10 @@
mLockscreenUserManager.getCurrentUserId());
if (showOverLockscreen) {
try {
- clickIntent.send();
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ clickIntent.send(opts.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Pending intent for " + key + " was cancelled");
}
@@ -684,6 +688,8 @@
try {
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
deviceIntent.send(options.toBundle());
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Device pending intent was canceled");
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 9bc66f6..01f047c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -43,9 +43,6 @@
*/
fun areNearbyMediaDevicesEnabled() = featureFlags.isEnabled(Flags.MEDIA_NEARBY_DEVICES)
- /** Check whether we show explicit indicator on UMO */
- fun isExplicitIndicatorEnabled() = featureFlags.isEnabled(Flags.MEDIA_EXPLICIT_INDICATOR)
-
/**
* If true, keep active media controls for the lifetime of the MediaSession, regardless of
* whether the underlying notification was dismissed
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 25899e5..f87f53c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -837,7 +837,7 @@
void adjustVolume(MediaDevice device, int volume) {
ThreadUtils.postOnBackgroundThread(() -> {
- device.requestSetVolume(volume);
+ mLocalMediaManager.adjustDeviceVolume(device, volume);
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index c3b5db4..310d234 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -15,6 +15,8 @@
package com.android.systemui.privacy
import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.res.Configuration
import android.util.AttributeSet
import android.view.Gravity.CENTER_VERTICAL
import android.view.Gravity.END
@@ -35,6 +37,7 @@
defStyleRes: Int = 0
) : LaunchableFrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView {
+ private var configuration: Configuration
private var iconMargin = 0
private var iconSize = 0
private var iconColor = 0
@@ -54,6 +57,7 @@
clipChildren = true
clipToPadding = true
iconsContainer = requireViewById(R.id.icons_container)
+ configuration = Configuration(context.resources.configuration)
updateResources()
}
@@ -102,6 +106,17 @@
R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
}
+ override fun onConfigurationChanged(newConfig: Configuration?) {
+ super.onConfigurationChanged(newConfig)
+ if (newConfig != null) {
+ val diff = newConfig.diff(configuration)
+ configuration.setTo(newConfig)
+ if (diff.and(ActivityInfo.CONFIG_DENSITY.or(ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
+ updateResources()
+ }
+ }
+ }
+
private fun updateResources() {
iconMargin = context.resources
.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
@@ -110,8 +125,11 @@
iconColor =
Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary)
+ val height = context.resources
+ .getDimensionPixelSize(R.dimen.ongoing_appops_chip_height)
val padding = context.resources
.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
+ iconsContainer.layoutParams.height = height
iconsContainer.setPaddingRelative(padding, 0, padding, 0)
iconsContainer.background = context.getDrawable(R.drawable.statusbar_privacy_chip_bg)
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/TvPrivacyChipsController.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvPrivacyChipsController.java
index 1c47799..5e4c797 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/television/TvPrivacyChipsController.java
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvPrivacyChipsController.java
@@ -348,9 +348,16 @@
return;
}
- TransitionManager.beginDelayedTransition(mChipsContainer, mCollapseTransition);
+ boolean hasExpandedChip = false;
for (PrivacyItemsChip chip : mChips) {
- chip.collapse();
+ hasExpandedChip |= chip.isExpanded();
+ }
+
+ if (mChipsContainer != null && hasExpandedChip) {
+ TransitionManager.beginDelayedTransition(mChipsContainer, mCollapseTransition);
+ for (PrivacyItemsChip chip : mChips) {
+ chip.collapse();
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 0a9839e..26c5219 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui.scene
+import com.android.systemui.scene.domain.startable.SceneContainerStartableModule
import com.android.systemui.scene.shared.model.SceneContainerConfigModule
import com.android.systemui.scene.ui.composable.SceneModule
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModelModule
@@ -25,6 +26,7 @@
includes =
[
SceneContainerConfigModule::class,
+ SceneContainerStartableModule::class,
SceneContainerViewModelModule::class,
SceneModule::class,
],
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index 1ebeced..0a86d35 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -19,6 +19,7 @@
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.scene.shared.model.SceneTransitionModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -45,6 +46,9 @@
containerConfigByName
.map { (containerName, _) -> containerName to MutableStateFlow(1f) }
.toMap()
+ private val sceneTransitionByContainerName:
+ Map<String, MutableStateFlow<SceneTransitionModel?>> =
+ containerConfigByName.keys.associateWith { MutableStateFlow(null) }
/**
* Returns the keys to all scenes in the container with the given name.
@@ -70,11 +74,43 @@
currentSceneByContainerName.setValue(containerName, scene)
}
+ /** Sets the scene transition in the container with the given name. */
+ fun setSceneTransition(containerName: String, from: SceneKey, to: SceneKey) {
+ check(allSceneKeys(containerName).contains(from)) {
+ """
+ Cannot set current scene key to "$from". The container "$containerName" does
+ not contain a scene with that key.
+ """
+ .trimIndent()
+ }
+ check(allSceneKeys(containerName).contains(to)) {
+ """
+ Cannot set current scene key to "$to". The container "$containerName" does
+ not contain a scene with that key.
+ """
+ .trimIndent()
+ }
+
+ sceneTransitionByContainerName.setValue(
+ containerName,
+ SceneTransitionModel(from = from, to = to)
+ )
+ }
+
/** The current scene in the container with the given name. */
fun currentScene(containerName: String): StateFlow<SceneModel> {
return currentSceneByContainerName.mutableOrError(containerName).asStateFlow()
}
+ /**
+ * Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene
+ * transition occurs. The flow begins with a `null` value at first, because the initial scene is
+ * not something that we transition to from another scene.
+ */
+ fun sceneTransitions(containerName: String): StateFlow<SceneTransitionModel?> {
+ return sceneTransitionByContainerName.mutableOrError(containerName).asStateFlow()
+ }
+
/** Sets whether the container with the given name is visible. */
fun setVisible(containerName: String, isVisible: Boolean) {
containerVisibilityByName.setValue(containerName, isVisible)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 1e55975..4582370 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -20,10 +20,21 @@
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.scene.shared.model.SceneTransitionModel
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow
-/** Business logic and app state accessors for the scene framework. */
+/**
+ * Generic business logic and app state accessors for the scene framework.
+ *
+ * Note that scene container specific business logic does not belong in this class. Instead, it
+ * should be hoisted to a class that is specific to that scene container, for an example, please see
+ * [SystemUiDefaultSceneContainerStartable].
+ *
+ * Also note that this class should not depend on state or logic of other modules or features.
+ * Instead, other feature modules should depend on and call into this class when their parts of the
+ * application state change.
+ */
@SysUISingleton
class SceneInteractor
@Inject
@@ -43,7 +54,9 @@
/** Sets the scene in the container with the given name. */
fun setCurrentScene(containerName: String, scene: SceneModel) {
+ val currentSceneKey = repository.currentScene(containerName).value.key
repository.setCurrentScene(containerName, scene)
+ repository.setSceneTransition(containerName, from = currentSceneKey, to = scene.key)
}
/** The current scene in the container with the given name. */
@@ -70,4 +83,13 @@
fun sceneTransitionProgress(containerName: String): StateFlow<Float> {
return repository.sceneTransitionProgress(containerName)
}
+
+ /**
+ * Scene transitions as pairs of keys. A new value is emitted exactly once, each time a scene
+ * transition occurs. The flow begins with a `null` value at first, because the initial scene is
+ * not something that we transition to from another scene.
+ */
+ fun sceneTransitions(containerName: String): StateFlow<SceneTransitionModel?> {
+ return repository.sceneTransitions(containerName)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt
new file mode 100644
index 0000000..b3de2d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartableModule.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.startable
+
+import com.android.systemui.CoreStartable
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface SceneContainerStartableModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(SystemUiDefaultSceneContainerStartable::class)
+ fun bind(impl: SystemUiDefaultSceneContainerStartable): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt
new file mode 100644
index 0000000..59f82f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.startable
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+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.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneContainerNames
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.SceneModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+/**
+ * Hooks up business logic that manipulates the state of the [SceneInteractor] for the default
+ * system UI scene container (the one named [SceneContainerNames.SYSTEM_UI_DEFAULT]) based on state
+ * from other systems.
+ */
+@SysUISingleton
+class SystemUiDefaultSceneContainerStartable
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val sceneInteractor: SceneInteractor,
+ private val authenticationInteractor: AuthenticationInteractor,
+ private val featureFlags: FeatureFlags,
+) : CoreStartable {
+
+ override fun start() {
+ if (featureFlags.isEnabled(Flags.SCENE_CONTAINER)) {
+ hydrateVisibility()
+ automaticallySwitchScenes()
+ }
+ }
+
+ /** Updates the visibility of the scene container based on the current scene. */
+ private fun hydrateVisibility() {
+ applicationScope.launch {
+ sceneInteractor
+ .currentScene(CONTAINER_NAME)
+ .map { it.key }
+ .distinctUntilChanged()
+ .collect { sceneKey ->
+ sceneInteractor.setVisible(CONTAINER_NAME, sceneKey != SceneKey.Gone)
+ }
+ }
+ }
+
+ /** Switches between scenes based on ever-changing application state. */
+ private fun automaticallySwitchScenes() {
+ applicationScope.launch {
+ authenticationInteractor.isUnlocked
+ .map { isUnlocked ->
+ val currentSceneKey = sceneInteractor.currentScene(CONTAINER_NAME).value.key
+ val isBypassEnabled = authenticationInteractor.isBypassEnabled.value
+ when {
+ isUnlocked ->
+ when (currentSceneKey) {
+ // When the device becomes unlocked in Bouncer, go to the Gone.
+ is SceneKey.Bouncer -> SceneKey.Gone
+ // When the device becomes unlocked in Lockscreen, go to Gone if
+ // bypass is enabled.
+ is SceneKey.Lockscreen -> SceneKey.Gone.takeIf { isBypassEnabled }
+ // We got unlocked while on a scene that's not Lockscreen or
+ // Bouncer, no need to change scenes.
+ else -> null
+ }
+ // When the device becomes locked, to Lockscreen.
+ !isUnlocked ->
+ when (currentSceneKey) {
+ // Already on lockscreen or bouncer, no need to change scenes.
+ is SceneKey.Lockscreen,
+ is SceneKey.Bouncer -> null
+ // We got locked while on a scene that's not Lockscreen or Bouncer,
+ // go to Lockscreen.
+ else -> SceneKey.Lockscreen
+ }
+ else -> null
+ }
+ }
+ .filterNotNull()
+ .collect { targetSceneKey ->
+ sceneInteractor.setCurrentScene(
+ containerName = CONTAINER_NAME,
+ scene = SceneModel(targetSceneKey),
+ )
+ }
+ }
+ }
+
+ companion object {
+ private const val CONTAINER_NAME = SceneContainerNames.SYSTEM_UI_DEFAULT
+ }
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotActivity.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
similarity index 63%
rename from packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotActivity.kt
rename to packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
index 2a55a80..c8f46a7 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ScreenshotActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.testing.screenshot
+package com.android.systemui.scene.shared.model
-import androidx.activity.ComponentActivity
-
-/** The Activity that is launched and whose content is set for screenshot tests. */
-class ScreenshotActivity : ComponentActivity()
+/** Models a transition between two scenes. */
+data class SceneTransitionModel(
+ /** The scene we transitioned away from. */
+ val from: SceneKey,
+ /** The scene we transitioned into. */
+ val to: SceneKey,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 2ad5429..c456be6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -2,19 +2,10 @@
import android.content.Context
import android.util.AttributeSet
-import androidx.activity.OnBackPressedDispatcher
-import androidx.activity.OnBackPressedDispatcherOwner
-import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.compose.ComposeFacade
-import com.android.systemui.lifecycle.repeatWhenAttached
+import android.view.View
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerConfig
-import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
-import kotlinx.coroutines.launch
/** A root view of the main SysUI window that supports scenes. */
class SceneWindowRootView(
@@ -30,45 +21,19 @@
containerConfig: SceneContainerConfig,
scenes: Set<Scene>,
) {
- val unsortedSceneByKey: Map<SceneKey, Scene> = scenes.associateBy { scene -> scene.key }
- val sortedSceneByKey: Map<SceneKey, Scene> = buildMap {
- containerConfig.sceneKeys.forEach { sceneKey ->
- val scene =
- checkNotNull(unsortedSceneByKey[sceneKey]) {
- "Scene not found for key \"$sceneKey\"!"
- }
-
- put(sceneKey, scene)
+ SceneWindowRootViewBinder.bind(
+ view = this@SceneWindowRootView,
+ viewModel = viewModel,
+ containerConfig = containerConfig,
+ scenes = scenes,
+ onVisibilityChangedInternal = { isVisible ->
+ super.setVisibility(if (isVisible) View.VISIBLE else View.INVISIBLE)
}
- }
+ )
+ }
- repeatWhenAttached {
- lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- setViewTreeOnBackPressedDispatcherOwner(
- object : OnBackPressedDispatcherOwner {
- override val onBackPressedDispatcher =
- OnBackPressedDispatcher().apply {
- setOnBackInvokedDispatcher(viewRootImpl.onBackInvokedDispatcher)
- }
-
- override val lifecycle: Lifecycle =
- this@repeatWhenAttached.lifecycle
- }
- )
-
- addView(
- ComposeFacade.createSceneContainerView(
- context = context,
- viewModel = viewModel,
- sceneByKey = sortedSceneByKey,
- )
- )
- }
-
- // Here when destroyed.
- removeAllViews()
- }
- }
+ override fun setVisibility(visibility: Int) {
+ // Do nothing. We don't want external callers to invoke this. Instead, we drive our own
+ // visibility from our view-binder.
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
new file mode 100644
index 0000000..5aa5fee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.ui.view
+
+import android.view.ViewGroup
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.OnBackPressedDispatcherOwner
+import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.scene.shared.model.Scene
+import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import kotlinx.coroutines.launch
+
+object SceneWindowRootViewBinder {
+
+ /** Binds between the view and view-model pertaining to a specific scene container. */
+ fun bind(
+ view: ViewGroup,
+ viewModel: SceneContainerViewModel,
+ containerConfig: SceneContainerConfig,
+ scenes: Set<Scene>,
+ onVisibilityChangedInternal: (isVisible: Boolean) -> Unit,
+ ) {
+ val unsortedSceneByKey: Map<SceneKey, Scene> = scenes.associateBy { scene -> scene.key }
+ val sortedSceneByKey: Map<SceneKey, Scene> = buildMap {
+ containerConfig.sceneKeys.forEach { sceneKey ->
+ val scene =
+ checkNotNull(unsortedSceneByKey[sceneKey]) {
+ "Scene not found for key \"$sceneKey\"!"
+ }
+
+ put(sceneKey, scene)
+ }
+ }
+
+ view.repeatWhenAttached {
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ view.setViewTreeOnBackPressedDispatcherOwner(
+ object : OnBackPressedDispatcherOwner {
+ override val onBackPressedDispatcher =
+ OnBackPressedDispatcher().apply {
+ setOnBackInvokedDispatcher(
+ view.viewRootImpl.onBackInvokedDispatcher
+ )
+ }
+
+ override val lifecycle: Lifecycle = this@repeatWhenAttached.lifecycle
+ }
+ )
+
+ view.addView(
+ ComposeFacade.createSceneContainerView(
+ context = view.context,
+ viewModel = viewModel,
+ sceneByKey = sortedSceneByKey,
+ )
+ )
+
+ launch {
+ viewModel.isVisible.collect { isVisible ->
+ onVisibilityChangedInternal(isVisible)
+ }
+ }
+ }
+
+ // Here when destroyed.
+ view.removeAllViews()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
index 3aefcb3..7e234ae 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionProxyReceiver.java
@@ -71,6 +71,8 @@
ActivityOptions opts = ActivityOptions.makeBasic();
opts.setDisallowEnterPictureInPictureWhileLaunching(
intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false));
+ opts.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
try {
actionIntent.send(context, 0, null, null, null, null, opts.toBundle());
if (intent.getBooleanExtra(ScreenshotController.EXTRA_OVERRIDE_TRANSITION, false)) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
index 13678b0..9e8ea3a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java
@@ -99,6 +99,8 @@
try {
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
+ options.setPendingIntentBackgroundActivityStartMode(
+ BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
intent.send(options.toBundle());
finisher.run();
} catch (PendingIntent.CanceledException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
index 9761f59..ef58b9d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
@@ -55,7 +55,8 @@
Log.d(TAG, "Executing smart action [" + actionType + "]:" + pendingIntent.getIntent());
}
ActivityOptions opts = ActivityOptions.makeBasic();
-
+ opts.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
try {
pendingIntent.send(context, 0, fillIn, null, null, null, opts.toBundle());
} catch (PendingIntent.CanceledException e) {
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 8879501..182e456 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -18,6 +18,7 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY;
import android.app.Activity;
import android.graphics.Rect;
@@ -29,8 +30,10 @@
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
@@ -38,34 +41,42 @@
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.AccessibilityManagerWrapper;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.List;
-import java.util.concurrent.Executor;
import javax.inject.Inject;
/** A dialog that provides controls for adjusting the screen brightness. */
public class BrightnessDialog extends Activity {
+ @VisibleForTesting
+ static final int DIALOG_TIMEOUT_MILLIS = 3000;
+
private BrightnessController mBrightnessController;
private final BrightnessSliderController.Factory mToggleSliderFactory;
private final UserTracker mUserTracker;
private final DisplayTracker mDisplayTracker;
- private final Executor mMainExecutor;
+ private final DelayableExecutor mMainExecutor;
private final Handler mBackgroundHandler;
+ private final AccessibilityManagerWrapper mAccessibilityMgr;
+ private Runnable mCancelTimeoutRunnable;
@Inject
public BrightnessDialog(
UserTracker userTracker,
DisplayTracker displayTracker,
BrightnessSliderController.Factory factory,
- @Main Executor mainExecutor,
- @Background Handler bgHandler) {
+ @Main DelayableExecutor mainExecutor,
+ @Background Handler bgHandler,
+ AccessibilityManagerWrapper accessibilityMgr) {
mUserTracker = userTracker;
mDisplayTracker = displayTracker;
mToggleSliderFactory = factory;
mMainExecutor = mainExecutor;
mBackgroundHandler = bgHandler;
+ mAccessibilityMgr = accessibilityMgr;
}
@@ -84,6 +95,7 @@
window.getDecorView();
window.setLayout(
WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
+ getTheme().applyStyle(R.style.Theme_SystemUI_QuickSettings, false);
setContentView(R.layout.brightness_mirror_container);
FrameLayout frame = findViewById(R.id.brightness_mirror_container);
@@ -121,6 +133,14 @@
}
@Override
+ protected void onResume() {
+ super.onResume();
+ if (triggeredByBrightnessKey()) {
+ scheduleTimeout();
+ }
+ }
+
+ @Override
protected void onPause() {
super.onPause();
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
@@ -138,9 +158,25 @@
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
|| keyCode == KeyEvent.KEYCODE_VOLUME_UP
|| keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
+ if (mCancelTimeoutRunnable != null) {
+ mCancelTimeoutRunnable.run();
+ }
finish();
}
return super.onKeyDown(keyCode, event);
}
+
+ private boolean triggeredByBrightnessKey() {
+ return getIntent().getBooleanExtra(EXTRA_FROM_BRIGHTNESS_KEY, false);
+ }
+
+ private void scheduleTimeout() {
+ if (mCancelTimeoutRunnable != null) {
+ mCancelTimeoutRunnable.run();
+ }
+ final int timeout = mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_TIMEOUT_MILLIS,
+ AccessibilityManager.FLAG_CONTENT_CONTROLS);
+ mCancelTimeoutRunnable = mMainExecutor.executeDelayed(this::finish, timeout);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index b6bb0ca..bb2be66 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
@@ -480,7 +480,6 @@
private void applyWindowLayoutParams() {
if (mDeferWindowLayoutParams == 0 && mLp != null && mLp.copyFrom(mLpChanged) != 0) {
- mLogger.logApplyingWindowLayoutParams(mLp);
Trace.beginSection("updateViewLayout");
mWindowManager.updateViewLayout(mWindowRootView, mLp);
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index 317d885..02f337a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -18,6 +18,8 @@
import android.view.MotionEvent;
+import com.android.systemui.CoreStartable;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -30,7 +32,7 @@
* these are coordinated with {@link StatusBarKeyguardViewManager} via
* {@link com.android.systemui.keyguard.KeyguardViewMediator} and others.
*/
-public interface ShadeController {
+public interface ShadeController extends CoreStartable {
/** Make our window larger and the shade expanded */
void instantExpandShade();
@@ -39,16 +41,24 @@
void instantCollapseShade();
/** See {@link #animateCollapseShade(int, boolean, boolean, float)}. */
- void animateCollapseShade();
+ default void animateCollapseShade() {
+ animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE);
+ }
/** See {@link #animateCollapseShade(int, boolean, boolean, float)}. */
- void animateCollapseShade(int flags);
+ default void animateCollapseShade(int flags) {
+ animateCollapseShade(flags, false, false, 1.0f);
+ }
/** See {@link #animateCollapseShade(int, boolean, boolean, float)}. */
- void animateCollapseShadeForced();
+ default void animateCollapseShadeForced() {
+ animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE, true, false, 1.0f);
+ }
/** See {@link #animateCollapseShade(int, boolean, boolean, float)}. */
- void animateCollapseShadeForcedDelayed();
+ default void animateCollapseShadeForcedDelayed() {
+ animateCollapseShade(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true, true, 1.0f);
+ }
/**
* Collapse the shade animated, showing the bouncer when on {@link StatusBarState#KEYGUARD} or
@@ -155,17 +165,14 @@
void onLaunchAnimationEnd(boolean launchIsFullScreen);
/** Sets the listener for when the visibility of the shade changes. */
- void setVisibilityListener(ShadeVisibilityListener listener);
+ default void setVisibilityListener(ShadeVisibilityListener listener) {}
/** */
- void setNotificationPresenter(NotificationPresenter presenter);
+ default void setNotificationPresenter(NotificationPresenter presenter) {}
/** */
- void setNotificationShadeWindowViewController(
- NotificationShadeWindowViewController notificationShadeWindowViewController);
-
- /** */
- void setShadeViewController(ShadeViewController shadeViewController);
+ default void setNotificationShadeWindowViewController(
+ NotificationShadeWindowViewController notificationShadeWindowViewController) {}
/** Listens for shade visibility changes. */
interface ShadeVisibilityListener {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
new file mode 100644
index 0000000..a8ef8e9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
@@ -0,0 +1,53 @@
+package com.android.systemui.shade
+
+import android.view.MotionEvent
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/** Empty implementation of ShadeController for variants of Android without shades. */
+@SysUISingleton
+open class ShadeControllerEmptyImpl @Inject constructor() : ShadeController {
+ override fun start() {}
+ override fun instantExpandShade() {}
+ override fun instantCollapseShade() {}
+ override fun animateCollapseShade(
+ flags: Int,
+ force: Boolean,
+ delayed: Boolean,
+ speedUpFactor: Float
+ ) {}
+ override fun animateExpandShade() {}
+ override fun animateExpandQs() {}
+ override fun postAnimateCollapseShade() {}
+ override fun postAnimateForceCollapseShade() {}
+ override fun postAnimateExpandQs() {}
+ override fun cancelExpansionAndCollapseShade() {}
+ override fun closeShadeIfOpen(): Boolean {
+ return false
+ }
+ override fun isKeyguard(): Boolean {
+ return false
+ }
+ override fun isShadeFullyOpen(): Boolean {
+ return false
+ }
+ override fun isExpandingOrCollapsing(): Boolean {
+ return false
+ }
+ override fun postOnShadeExpanded(action: Runnable?) {}
+ override fun addPostCollapseAction(action: Runnable?) {}
+ override fun runPostCollapseRunnables() {}
+ override fun collapseShade(): Boolean {
+ return false
+ }
+ override fun collapseShade(animate: Boolean) {}
+ override fun collapseOnMainThread() {}
+ override fun makeExpandedInvisible() {}
+ override fun makeExpandedVisible(force: Boolean) {}
+ override fun isExpandedVisible(): Boolean {
+ return false
+ }
+ override fun onStatusBarTouch(event: MotionEvent?) {}
+ override fun onLaunchAnimationCancelled(isLaunchForActivity: Boolean) {}
+ override fun onLaunchAnimationEnd(launchIsFullScreen: Boolean) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index b92afac..22c63817 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -63,6 +63,7 @@
private final StatusBarWindowController mStatusBarWindowController;
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final Lazy<ShadeViewController> mShadeViewControllerLazy;
private final Lazy<AssistManager> mAssistManagerLazy;
private final Lazy<NotificationGutsManager> mGutsManager;
@@ -70,8 +71,6 @@
private boolean mExpandedVisible;
- // TODO(b/237661616): Rename this variable to mShadeViewController.
- private ShadeViewController mNotificationPanelViewController;
private NotificationPresenter mPresenter;
private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
private ShadeVisibilityListener mShadeVisibilityListener;
@@ -87,11 +86,13 @@
DeviceProvisionedController deviceProvisionedController,
NotificationShadeWindowController notificationShadeWindowController,
WindowManager windowManager,
+ Lazy<ShadeViewController> shadeViewControllerLazy,
Lazy<AssistManager> assistManagerLazy,
Lazy<NotificationGutsManager> gutsManager
) {
mCommandQueue = commandQueue;
mMainExecutor = mainExecutor;
+ mShadeViewControllerLazy = shadeViewControllerLazy;
mStatusBarStateController = statusBarStateController;
mStatusBarWindowController = statusBarWindowController;
mDeviceProvisionedController = deviceProvisionedController;
@@ -107,31 +108,11 @@
public void instantExpandShade() {
// Make our window larger and the panel expanded.
makeExpandedVisible(true /* force */);
- mNotificationPanelViewController.expand(false /* animate */);
+ getShadeViewController().expand(false /* animate */);
mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */);
}
@Override
- public void animateCollapseShade() {
- animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE);
- }
-
- @Override
- public void animateCollapseShade(int flags) {
- animateCollapseShade(flags, false, false, 1.0f);
- }
-
- @Override
- public void animateCollapseShadeForced() {
- animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE, true, false, 1.0f);
- }
-
- @Override
- public void animateCollapseShadeForcedDelayed() {
- animateCollapseShade(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true, true, 1.0f);
- }
-
- @Override
public void animateCollapseShade(int flags, boolean force, boolean delayed,
float speedUpFactor) {
if (!force && mStatusBarStateController.getState() != StatusBarState.SHADE) {
@@ -143,13 +124,13 @@
"animateCollapse(): mExpandedVisible=" + mExpandedVisible + "flags=" + flags);
}
if (getNotificationShadeWindowView() != null
- && mNotificationPanelViewController.canBeCollapsed()
+ && getShadeViewController().canBeCollapsed()
&& (flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) {
// release focus immediately to kick off focus change transition
mNotificationShadeWindowController.setNotificationShadeFocusable(false);
mNotificationShadeWindowViewController.cancelExpandHelper();
- mNotificationPanelViewController.collapse(true, delayed, speedUpFactor);
+ getShadeViewController().collapse(true, delayed, speedUpFactor);
}
}
@@ -158,7 +139,7 @@
if (!mCommandQueue.panelsEnabled()) {
return;
}
- mNotificationPanelViewController.expandToNotifications();
+ getShadeViewController().expandToNotifications();
}
@Override
@@ -169,12 +150,12 @@
// Settings are not available in setup
if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
- mNotificationPanelViewController.expandToQs();
+ getShadeViewController().expandToQs();
}
@Override
public boolean closeShadeIfOpen() {
- if (!mNotificationPanelViewController.isFullyCollapsed()) {
+ if (!getShadeViewController().isFullyCollapsed()) {
mCommandQueue.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
notifyVisibilityChanged(false);
@@ -190,12 +171,12 @@
@Override
public boolean isShadeFullyOpen() {
- return mNotificationPanelViewController.isShadeFullyExpanded();
+ return getShadeViewController().isShadeFullyExpanded();
}
@Override
public boolean isExpandingOrCollapsing() {
- return mNotificationPanelViewController.isExpandingOrCollapsing();
+ return getShadeViewController().isExpandingOrCollapsing();
}
@Override
public void postAnimateCollapseShade() {
@@ -214,13 +195,13 @@
@Override
public void postOnShadeExpanded(Runnable executable) {
- mNotificationPanelViewController.addOnGlobalLayoutListener(
+ getShadeViewController().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (getNotificationShadeWindowView().isVisibleToUser()) {
- mNotificationPanelViewController.removeOnGlobalLayoutListener(this);
- mNotificationPanelViewController.postToView(executable);
+ getShadeViewController().removeOnGlobalLayoutListener(this);
+ getShadeViewController().postToView(executable);
}
}
});
@@ -244,7 +225,7 @@
@Override
public boolean collapseShade() {
- if (!mNotificationPanelViewController.isFullyCollapsed()) {
+ if (!getShadeViewController().isFullyCollapsed()) {
// close the shade if it was open
animateCollapseShadeForcedDelayed();
notifyVisibilityChanged(false);
@@ -272,10 +253,10 @@
@Override
public void cancelExpansionAndCollapseShade() {
- if (mNotificationPanelViewController.isTracking()) {
+ if (getShadeViewController().isTracking()) {
mNotificationShadeWindowViewController.cancelCurrentTouch();
}
- if (mNotificationPanelViewController.isPanelExpanded()
+ if (getShadeViewController().isPanelExpanded()
&& mStatusBarStateController.getState() == StatusBarState.SHADE) {
animateCollapseShade();
}
@@ -331,7 +312,7 @@
@Override
public void instantCollapseShade() {
- mNotificationPanelViewController.instantCollapse();
+ getShadeViewController().instantCollapse();
runPostCollapseRunnables();
}
@@ -362,7 +343,7 @@
}
// Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
- mNotificationPanelViewController.collapse(false, false, 1.0f);
+ getShadeViewController().collapse(false, false, 1.0f);
mExpandedVisible = false;
notifyVisibilityChanged(false);
@@ -384,7 +365,7 @@
notifyExpandedVisibleChanged(false);
mCommandQueue.recomputeDisableFlags(
mDisplayId,
- mNotificationPanelViewController.shouldHideStatusBarIconsWhenExpanded());
+ getShadeViewController().shouldHideStatusBarIconsWhenExpanded());
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
// the bouncer appear animation.
@@ -426,11 +407,14 @@
return mNotificationShadeWindowViewController.getView();
}
+ private ShadeViewController getShadeViewController() {
+ return mShadeViewControllerLazy.get();
+ }
+
@Override
- public void setShadeViewController(ShadeViewController shadeViewController) {
- mNotificationPanelViewController = shadeViewController;
- mNotificationPanelViewController.setTrackingStartedListener(this::runPostCollapseRunnables);
- mNotificationPanelViewController.setOpenCloseListener(
+ public void start() {
+ getShadeViewController().setTrackingStartedListener(this::runPostCollapseRunnables);
+ getShadeViewController().setOpenCloseListener(
new OpenCloseListener() {
@Override
public void onClosingFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index 8789a8b..411f91f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -131,6 +131,7 @@
private val date: TextView = header.findViewById(R.id.date)
private val iconContainer: StatusIconContainer = header.findViewById(R.id.statusIcons)
private val mShadeCarrierGroup: ShadeCarrierGroup = header.findViewById(R.id.carrier_group)
+ private val systemIcons: View = header.findViewById(R.id.shade_header_system_icons)
private var roundedCorners = 0
private var cutout: DisplayCutout? = null
@@ -254,6 +255,14 @@
header.paddingRight,
header.paddingBottom
)
+ systemIcons.setPaddingRelative(
+ resources.getDimensionPixelSize(
+ R.dimen.shade_header_system_icons_padding_start
+ ),
+ systemIcons.paddingTop,
+ resources.getDimensionPixelSize(R.dimen.shade_header_system_icons_padding_end),
+ systemIcons.paddingBottom
+ )
}
override fun onDensityOrFontScaleChanged() {
@@ -266,6 +275,7 @@
lastInsets?.let { updateConstraintsForInsets(header, it) }
updateResources()
updateCarrierGroupPadding()
+ clock.onDensityOrFontScaleChanged()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 2c560c9..e2e633a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -59,7 +59,7 @@
import javax.inject.Provider
/** Module for classes related to the notification shade. */
-@Module
+@Module(includes = [StartShadeModule::class])
abstract class ShadeModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
index 51a27cf..e7a397b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLogger.kt
@@ -16,14 +16,13 @@
package com.android.systemui.shade
-import android.view.WindowManager
-import com.android.systemui.log.dagger.ShadeWindowLog
import com.android.systemui.log.ConstantStringsLogger
import com.android.systemui.log.ConstantStringsLoggerImpl
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.core.LogMessage
+import com.android.systemui.log.dagger.ShadeWindowLog
import javax.inject.Inject
private const val TAG = "systemui.shadewindow"
@@ -31,15 +30,6 @@
class ShadeWindowLogger @Inject constructor(@ShadeWindowLog private val buffer: LogBuffer) :
ConstantStringsLogger by ConstantStringsLoggerImpl(buffer, TAG) {
- fun logApplyingWindowLayoutParams(lp: WindowManager.LayoutParams) {
- buffer.log(
- TAG,
- DEBUG,
- { str1 = lp.toString() },
- { "Applying new window layout params: $str1" }
- )
- }
-
fun logNewState(state: Any) {
buffer.log(
TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/StartShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/StartShadeModule.kt
new file mode 100644
index 0000000..384fb95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/StartShadeModule.kt
@@ -0,0 +1,15 @@
+package com.android.systemui.shade
+
+import com.android.systemui.CoreStartable
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+internal abstract class StartShadeModule {
+ @Binds
+ @IntoMap
+ @ClassKey(ShadeController::class)
+ abstract fun bind(shadeController: ShadeController): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ConnectedDisplayChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ConnectedDisplayChip.kt
new file mode 100644
index 0000000..76636ab8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ConnectedDisplayChip.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.res.Configuration
+import android.util.AttributeSet
+import android.widget.FrameLayout
+import com.android.systemui.R
+import com.android.systemui.statusbar.events.BackgroundAnimatableView
+
+/** Chip that appears in the status bar when an external display is connected. */
+class ConnectedDisplayChip
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) :
+ FrameLayout(context, attrs), BackgroundAnimatableView {
+
+ private val iconContainer: FrameLayout
+ init {
+ inflate(context, R.layout.connected_display_chip, this)
+ iconContainer = requireViewById(R.id.icons_rounded_container)
+ }
+
+ /**
+ * When animating as a chip in the status bar, we want to animate the width for the rounded
+ * container. We have to subtract our own top and left offset because the bounds come to us as
+ * absolute on-screen bounds.
+ */
+ override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+ iconContainer.setLeftTopRightBottom(l - left, t - top, r - left, b - top)
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ updateResources()
+ }
+
+ @SuppressLint("UseCompatLoadingForDrawables")
+ private fun updateResources() {
+ iconContainer.background = context.getDrawable(R.drawable.statusbar_chip_bg)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 42ebaa3..73d8445 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -29,6 +29,7 @@
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
@@ -43,6 +44,7 @@
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
import static com.android.systemui.log.core.LogLevel.ERROR;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.app.AlarmManager;
import android.app.admin.DevicePolicyManager;
@@ -96,6 +98,7 @@
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.util.IndicationHelper;
import com.android.systemui.log.core.LogLevel;
import com.android.systemui.plugins.FalsingManager;
@@ -114,6 +117,7 @@
import java.text.NumberFormat;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -171,7 +175,7 @@
public KeyguardIndicationRotateTextViewController mRotateTextViewController;
private BroadcastReceiver mBroadcastReceiver;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
-
+ private KeyguardInteractor mKeyguardInteractor;
private String mPersistentUnlockMessage;
private String mAlignmentIndication;
private CharSequence mTrustGrantedIndication;
@@ -205,7 +209,17 @@
private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
private boolean mDozing;
+ private boolean mIsActiveDreamLockscreenHosted;
private final ScreenLifecycle mScreenLifecycle;
+ @VisibleForTesting
+ final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback =
+ (Boolean isLockscreenHosted) -> {
+ if (mIsActiveDreamLockscreenHosted == isLockscreenHosted) {
+ return;
+ }
+ mIsActiveDreamLockscreenHosted = isLockscreenHosted;
+ updateDeviceEntryIndication(false);
+ };
private final ScreenLifecycle.Observer mScreenObserver =
new ScreenLifecycle.Observer() {
@Override
@@ -261,7 +275,8 @@
UserTracker userTracker,
BouncerMessageInteractor bouncerMessageInteractor,
FeatureFlags flags,
- IndicationHelper indicationHelper
+ IndicationHelper indicationHelper,
+ KeyguardInteractor keyguardInteractor
) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -289,6 +304,7 @@
mBouncerMessageInteractor = bouncerMessageInteractor;
mFeatureFlags = flags;
mIndicationHelper = indicationHelper;
+ mKeyguardInteractor = keyguardInteractor;
mFaceAcquiredMessageDeferral = faceHelpMessageDeferral;
mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
@@ -371,6 +387,10 @@
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, intentFilter);
}
+ if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
+ collectFlow(mIndicationArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(),
+ mIsActiveDreamLockscreenHostedCallback);
+ }
}
/**
@@ -878,6 +898,12 @@
return;
}
+ // Device is dreaming and the dream is hosted in lockscreen
+ if (mIsActiveDreamLockscreenHosted) {
+ mIndicationArea.setVisibility(GONE);
+ return;
+ }
+
// A few places might need to hide the indication, so always start by making it visible
mIndicationArea.setVisibility(VISIBLE);
@@ -1069,6 +1095,7 @@
pw.println(" mBiometricMessageFollowUp: " + mBiometricMessageFollowUp);
pw.println(" mBatteryLevel: " + mBatteryLevel);
pw.println(" mBatteryPresent: " + mBatteryPresent);
+ pw.println(" mIsActiveDreamLockscreenHosted: " + mIsActiveDreamLockscreenHosted);
pw.println(" AOD text: " + (
mTopIndicationView == null ? null : mTopIndicationView.getText()));
pw.println(" computePowerIndication(): " + computePowerIndication());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index e6e3e7e..ea5ca27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -19,6 +19,7 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
+import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.admin.DevicePolicyManager;
@@ -158,7 +159,11 @@
final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
if (intentSender != null) {
try {
- mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ mContext.startIntentSender(intentSender, null, 0, 0, 0,
+ options.toBundle());
} catch (IntentSender.SendIntentException e) {
/* ignore */
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 91c08a0..cff71d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -26,6 +26,7 @@
import android.app.ActivityManager;
import android.app.Notification;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -41,18 +42,19 @@
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
-import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
import android.util.Property;
import android.util.TypedValue;
import android.view.ViewDebug;
+import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Interpolator;
import androidx.core.graphics.ColorUtils;
import com.android.app.animation.Interpolators;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
@@ -131,10 +133,12 @@
}
};
- private boolean mAlwaysScaleIcon;
private int mStatusBarIconDrawingSizeIncreased = 1;
- private int mStatusBarIconDrawingSize = 1;
- private int mStatusBarIconSize = 1;
+ @VisibleForTesting int mStatusBarIconDrawingSize = 1;
+
+ @VisibleForTesting int mOriginalStatusBarIconSize = 1;
+ @VisibleForTesting int mNewStatusBarIconSize = 1;
+ @VisibleForTesting float mScaleToFitNewIconSize = 1;
private StatusBarIcon mIcon;
@ViewDebug.ExportedProperty private String mSlot;
private Drawable mNumberBackground;
@@ -144,7 +148,7 @@
private String mNumberText;
private StatusBarNotification mNotification;
private final boolean mBlocked;
- private int mDensity;
+ private Configuration mConfiguration;
private boolean mNightMode;
private float mIconScale = 1.0f;
private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -198,30 +202,20 @@
mNumberPain.setAntiAlias(true);
setNotification(sbn);
setScaleType(ScaleType.CENTER);
- mDensity = context.getResources().getDisplayMetrics().densityDpi;
- Configuration configuration = context.getResources().getConfiguration();
- mNightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ mConfiguration = new Configuration(context.getResources().getConfiguration());
+ mNightMode = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
initializeDecorColor();
reloadDimens();
maybeUpdateIconScaleDimens();
}
- public StatusBarIconView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mDozer = new NotificationIconDozeHelper(context);
- mBlocked = false;
- mAlwaysScaleIcon = true;
- reloadDimens();
- maybeUpdateIconScaleDimens();
- mDensity = context.getResources().getDisplayMetrics().densityDpi;
- }
-
/** Should always be preceded by {@link #reloadDimens()} */
- private void maybeUpdateIconScaleDimens() {
+ @VisibleForTesting
+ public void maybeUpdateIconScaleDimens() {
// We do not resize and scale system icons (on the right), only notification icons (on the
// left).
- if (mNotification != null || mAlwaysScaleIcon) {
+ if (isNotification()) {
updateIconScaleForNotifications();
} else {
updateIconScaleForSystemIcons();
@@ -229,22 +223,63 @@
}
private void updateIconScaleForNotifications() {
+ float iconScale;
+ // we need to scale the image size to be same as the original size
+ // (fit mOriginalStatusBarIconSize), then we can scale it with mScaleToFitNewIconSize
+ // to fit mNewStatusBarIconSize
+ float scaleToOriginalDrawingSize = 1.0f;
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ if (getDrawable() != null && (lp != null && lp.width > 0 && lp.height > 0)) {
+ final int iconViewWidth = lp.width;
+ final int iconViewHeight = lp.height;
+ // first we estimate the image exact size when put the drawable in scaled iconView size,
+ // then we can compute the scaleToOriginalDrawingSize to make the image size fit in
+ // mOriginalStatusBarIconSize
+ final int drawableWidth = getDrawable().getIntrinsicWidth();
+ final int drawableHeight = getDrawable().getIntrinsicHeight();
+ float scaleToFitIconView = Math.min(
+ (float) iconViewWidth / drawableWidth,
+ (float) iconViewHeight / drawableHeight);
+ // if the drawable size <= the icon view size, the drawable won't be scaled
+ if (scaleToFitIconView > 1.0f) {
+ scaleToFitIconView = 1.0f;
+ }
+ final float scaledImageWidth = drawableWidth * scaleToFitIconView;
+ final float scaledImageHeight = drawableHeight * scaleToFitIconView;
+ // if the scaled image size <= mOriginalStatusBarIconSize, we don't need to enlarge it
+ scaleToOriginalDrawingSize = Math.min(
+ (float) mOriginalStatusBarIconSize / scaledImageWidth,
+ (float) mOriginalStatusBarIconSize / scaledImageHeight);
+ if (scaleToOriginalDrawingSize > 1.0f) {
+ scaleToOriginalDrawingSize = 1.0f;
+ }
+ }
+ iconScale = scaleToOriginalDrawingSize;
+
final float imageBounds = mIncreasedSize ?
mStatusBarIconDrawingSizeIncreased : mStatusBarIconDrawingSize;
- final int outerBounds = mStatusBarIconSize;
- mIconScale = imageBounds / (float)outerBounds;
+ final int originalOuterBounds = mOriginalStatusBarIconSize;
+ iconScale = iconScale * (imageBounds / (float) originalOuterBounds);
+
+ // scale image to fit new icon size
+ mIconScale = iconScale * mScaleToFitNewIconSize;
+
updatePivot();
}
// Makes sure that all icons are scaled to the same height (15dp). If we cannot get a height
// for the icon, it uses the default SCALE (15f / 17f) which is the old behavior
private void updateIconScaleForSystemIcons() {
+ float iconScale;
float iconHeight = getIconHeight();
if (iconHeight != 0) {
- mIconScale = mSystemIconDesiredHeight / iconHeight;
+ iconScale = mSystemIconDesiredHeight / iconHeight;
} else {
- mIconScale = mSystemIconDefaultScale;
+ iconScale = mSystemIconDefaultScale;
}
+
+ // scale image to fit new icon size
+ mIconScale = iconScale * mScaleToFitNewIconSize;
}
private float getIconHeight() {
@@ -267,12 +302,10 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- int density = newConfig.densityDpi;
- if (density != mDensity) {
- mDensity = density;
- reloadDimens();
- updateDrawable();
- maybeUpdateIconScaleDimens();
+ final int configDiff = newConfig.diff(mConfiguration);
+ mConfiguration.setTo(newConfig);
+ if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
+ updateIconDimens();
}
boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
@@ -282,11 +315,22 @@
}
}
+ /**
+ * Update the icon dimens and drawable with current resources
+ */
+ public void updateIconDimens() {
+ reloadDimens();
+ updateDrawable();
+ maybeUpdateIconScaleDimens();
+ }
+
private void reloadDimens() {
boolean applyRadius = mDotRadius == mStaticDotRadius;
Resources res = getResources();
mStaticDotRadius = res.getDimensionPixelSize(R.dimen.overflow_dot_radius);
- mStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
+ mOriginalStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
+ mNewStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size_sp);
+ mScaleToFitNewIconSize = (float) mNewStatusBarIconSize / mOriginalStatusBarIconSize;
mStatusBarIconDrawingSizeIncreased =
res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark);
mStatusBarIconDrawingSize =
@@ -309,6 +353,10 @@
maybeUpdateIconScaleDimens();
}
+ private boolean isNotification() {
+ return mNotification != null;
+ }
+
private static boolean streq(String a, String b) {
if (a == b) {
return true;
@@ -416,7 +464,7 @@
Drawable getIcon(StatusBarIcon icon) {
Context notifContext = getContext();
- if (mNotification != null) {
+ if (isNotification()) {
notifContext = mNotification.getPackageContext(getContext());
}
return getIcon(getContext(), notifContext != null ? notifContext : getContext(), icon);
@@ -471,7 +519,7 @@
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
- if (mNotification != null) {
+ if (isNotification()) {
event.setParcelableData(mNotification.getNotification());
}
}
@@ -491,11 +539,29 @@
}
@Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (!isNotification()) {
+ // for system icons, calculated measured width from super is for image drawable real
+ // width (17dp). We may scale the image with font scale, so we also need to scale the
+ // measured width so that scaled measured width and image width would be fit.
+ int measuredWidth = getMeasuredWidth();
+ int measuredHeight = getMeasuredHeight();
+ setMeasuredDimension((int) (measuredWidth * mScaleToFitNewIconSize), measuredHeight);
+ }
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
+ // In this method, for width/height division computation we intend to discard the
+ // fractional part as the original behavior.
if (mIconAppearAmount > 0.0f) {
canvas.save();
+ int px = getWidth() / 2;
+ int py = getHeight() / 2;
canvas.scale(mIconScale * mIconAppearAmount, mIconScale * mIconAppearAmount,
- getWidth() / 2, getHeight() / 2);
+ (float) px, (float) py);
super.onDraw(canvas);
canvas.restore();
}
@@ -512,10 +578,15 @@
} else {
float fadeOutAmount = mDotAppearAmount - 1.0f;
alpha = alpha * (1.0f - fadeOutAmount);
- radius = NotificationUtils.interpolate(mDotRadius, getWidth() / 4, fadeOutAmount);
+ int end = getWidth() / 4;
+ radius = NotificationUtils.interpolate(mDotRadius, (float) end, fadeOutAmount);
}
mDotPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(mStatusBarIconSize / 2, getHeight() / 2, radius, mDotPaint);
+ int cx = mNewStatusBarIconSize / 2;
+ int cy = getHeight() / 2;
+ canvas.drawCircle(
+ (float) cx, (float) cy,
+ radius, mDotPaint);
}
}
@@ -624,7 +695,7 @@
}
private void initializeDecorColor() {
- if (mNotification != null) {
+ if (isNotification()) {
setDecorColor(getContext().getColor(mNightMode
? com.android.internal.R.color.notification_default_color_dark
: com.android.internal.R.color.notification_default_color_light));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index fdad101..d6f6c2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -135,7 +135,7 @@
mDotView = new StatusBarIconView(mContext, mSlot, null);
mDotView.setVisibleState(STATE_DOT);
- int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size);
+ int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size_sp);
LayoutParams lp = new LayoutParams(width, width);
lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
addView(mDotView, lp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index decc70d..8d7214d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -164,7 +164,7 @@
mDotView = new StatusBarIconView(mContext, mSlot, null);
mDotView.setVisibleState(STATE_DOT);
- int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size);
+ int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size_sp);
LayoutParams lp = new LayoutParams(width, width);
lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
addView(mDotView, lp);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
index e5849c0..bde298d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
@@ -24,6 +24,7 @@
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.statusbar.BatteryStatusChip
+import com.android.systemui.statusbar.ConnectedDisplayChip
typealias ViewCreator = (context: Context) -> BackgroundAnimatableView
@@ -87,6 +88,23 @@
}
}
+/** Event that triggers a connected display chip in the status bar. */
+class ConnectedDisplayEvent : StatusEvent {
+ /** Priority is set higher than [BatteryEvent]. */
+ override val priority = 60
+ override var forceVisible = false
+ override val showAnimation = true
+ override var contentDescription: String? = ""
+
+ override val viewCreator: ViewCreator = { context ->
+ ConnectedDisplayChip(context)
+ }
+
+ override fun toString(): String {
+ return javaClass.simpleName
+ }
+}
+
/** open only for testing purposes. (See [FakeStatusEvent.kt]) */
open class PrivacyEvent(override val showAnimation: Boolean = true) : StatusEvent {
override var contentDescription: String? = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
index 776956a..5639000 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
@@ -30,9 +30,11 @@
import androidx.core.animation.AnimatorListenerAdapter
import androidx.core.animation.AnimatorSet
import androidx.core.animation.ValueAnimator
+import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
@@ -46,7 +48,7 @@
private val context: Context,
private val statusBarWindowController: StatusBarWindowController,
private val contentInsetsProvider: StatusBarContentInsetsProvider,
- private val featureFlags: FeatureFlags
+ private val featureFlags: FeatureFlags,
) : SystemStatusAnimationCallback {
private lateinit var animationWindowView: FrameLayout
@@ -56,7 +58,8 @@
// Left for LTR, Right for RTL
private var animationDirection = LEFT
- private var chipBounds = Rect()
+
+ @VisibleForTesting var chipBounds = Rect()
private val chipWidth get() = chipBounds.width()
private val chipRight get() = chipBounds.right
private val chipLeft get() = chipBounds.left
@@ -69,7 +72,7 @@
private var animRect = Rect()
// TODO: move to dagger
- private var initialized = false
+ @VisibleForTesting var initialized = false
/**
* Give the chip controller a chance to inflate and configure the chip view before we start
@@ -98,23 +101,7 @@
View.MeasureSpec.makeMeasureSpec(
(animationWindowView.parent as View).height, AT_MOST))
- // decide which direction we're animating from, and then set some screen coordinates
- val contentRect = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()
- val chipTop = ((animationWindowView.parent as View).height - it.view.measuredHeight) / 2
- val chipBottom = chipTop + it.view.measuredHeight
- val chipRight: Int
- val chipLeft: Int
- when (animationDirection) {
- LEFT -> {
- chipRight = contentRect.right
- chipLeft = contentRect.right - it.chipWidth
- }
- else /* RIGHT */ -> {
- chipLeft = contentRect.left
- chipRight = contentRect.left + it.chipWidth
- }
- }
- chipBounds = Rect(chipLeft, chipTop, chipRight, chipBottom)
+ updateChipBounds(it, contentInsetsProvider.getStatusBarContentAreaForCurrentRotation())
}
}
@@ -253,16 +240,67 @@
return animSet
}
- private fun init() {
+ fun init() {
initialized = true
themedContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
animationWindowView = LayoutInflater.from(themedContext)
.inflate(R.layout.system_event_animation_window, null) as FrameLayout
- val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
- lp.gravity = Gravity.END or Gravity.CENTER_VERTICAL
+ // Matches status_bar.xml
+ val height = themedContext.resources.getDimensionPixelSize(R.dimen.status_bar_height)
+ val lp = FrameLayout.LayoutParams(MATCH_PARENT, height)
+ lp.gravity = Gravity.END or Gravity.TOP
statusBarWindowController.addViewToWindow(animationWindowView, lp)
animationWindowView.clipToPadding = false
animationWindowView.clipChildren = false
+
+ // Use contentInsetsProvider rather than configuration controller, since we only care
+ // about status bar dimens
+ contentInsetsProvider.addCallback(object : StatusBarContentInsetsChangedListener {
+ override fun onStatusBarContentInsetsChanged() {
+ val newContentArea = contentInsetsProvider
+ .getStatusBarContentAreaForCurrentRotation()
+ updateDimens(newContentArea)
+
+ // If we are currently animating, we have to re-solve for the chip bounds. If we're
+ // not animating then [prepareChipAnimation] will take care of it for us
+ currentAnimatedView?.let {
+ updateChipBounds(it, newContentArea)
+ }
+ }
+ })
+ }
+
+ private fun updateDimens(contentArea: Rect) {
+ val lp = animationWindowView.layoutParams as FrameLayout.LayoutParams
+ lp.height = contentArea.height()
+
+ animationWindowView.layoutParams = lp
+ }
+
+ /**
+ * Use the current status bar content area and the current chip's measured size to update
+ * the animation rect and chipBounds. This method can be called at any time and will update
+ * the current animation values properly during e.g. a rotation.
+ */
+ private fun updateChipBounds(chip: BackgroundAnimatableView, contentArea: Rect) {
+ // decide which direction we're animating from, and then set some screen coordinates
+ val chipTop = (contentArea.bottom - chip.view.measuredHeight) / 2
+ val chipBottom = chipTop + chip.view.measuredHeight
+ val chipRight: Int
+ val chipLeft: Int
+
+ when (animationDirection) {
+ LEFT -> {
+ chipRight = contentArea.right
+ chipLeft = contentArea.right - chip.chipWidth
+ }
+ else /* RIGHT */ -> {
+ chipLeft = contentArea.left
+ chipRight = contentArea.left + chip.chipWidth
+ }
+ }
+ chipBounds = Rect(chipLeft, chipTop, chipRight, chipBottom)
+ animRect.set(chipBounds)
}
private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
index 26fd230..23edf17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
@@ -22,6 +22,9 @@
import android.provider.DeviceConfig.NAMESPACE_PRIVACY
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.privacy.PrivacyChipBuilder
@@ -30,29 +33,45 @@
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
/**
- * Listens for system events (battery, privacy, connectivity) and allows listeners
- * to show status bar animations when they happen
+ * Listens for system events (battery, privacy, connectivity) and allows listeners to show status
+ * bar animations when they happen
*/
@SysUISingleton
-class SystemEventCoordinator @Inject constructor(
+class SystemEventCoordinator
+@Inject
+constructor(
private val systemClock: SystemClock,
private val batteryController: BatteryController,
private val privacyController: PrivacyItemController,
private val context: Context,
- private val featureFlags: FeatureFlags
+ private val featureFlags: FeatureFlags,
+ @Application private val appScope: CoroutineScope,
+ connectedDisplayInteractor: ConnectedDisplayInteractor
) {
+ private val onDisplayConnectedFlow =
+ connectedDisplayInteractor.connectedDisplayState
+ .filter { it != State.DISCONNECTED }
+
+ private var connectedDisplayCollectionJob: Job? = null
private lateinit var scheduler: SystemStatusAnimationScheduler
fun startObserving() {
batteryController.addCallback(batteryStateListener)
privacyController.addCallback(privacyStateListener)
+ startConnectedDisplayCollection()
}
fun stopObserving() {
batteryController.removeCallback(batteryStateListener)
privacyController.removeCallback(privacyStateListener)
+ connectedDisplayCollectionJob?.cancel()
}
fun attachScheduler(s: SystemStatusAnimationScheduler) {
@@ -80,6 +99,13 @@
scheduler.onStatusEvent(event)
}
+ private fun startConnectedDisplayCollection() {
+ connectedDisplayCollectionJob =
+ onDisplayConnectedFlow
+ .onEach { scheduler.onStatusEvent(ConnectedDisplayEvent()) }
+ .launchIn(appScope)
+ }
+
private val batteryStateListener = object : BatteryController.BatteryStateChangeCallback {
private var plugged = false
private var stateKnown = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 2fa070c..07eb8a00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -28,12 +28,9 @@
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionState
-import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.expansionChanges
-import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
@@ -50,30 +47,29 @@
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import java.io.PrintWriter
import javax.inject.Inject
-import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.emitAll
-import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
/**
* Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
- * headers on the lockscreen.
+ * headers on the lockscreen. If enabled, it will also track and hide seen notifications on the
+ * lockscreen.
*/
@CoordinatorScope
class KeyguardCoordinator
@@ -86,7 +82,6 @@
private val keyguardRepository: KeyguardRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
private val logger: KeyguardCoordinatorLogger,
- private val notifPipelineFlags: NotifPipelineFlags,
@Application private val scope: CoroutineScope,
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
private val secureSettings: SecureSettings,
@@ -95,6 +90,8 @@
) : Coordinator, Dumpable {
private val unseenNotifications = mutableSetOf<NotificationEntry>()
+ private val unseenEntryAdded = MutableSharedFlow<NotificationEntry>(extraBufferCapacity = 1)
+ private val unseenEntryRemoved = MutableSharedFlow<NotificationEntry>(extraBufferCapacity = 1)
private var unseenFilterEnabled = false
override fun attach(pipeline: NotifPipeline) {
@@ -109,79 +106,130 @@
private fun attachUnseenFilter(pipeline: NotifPipeline) {
pipeline.addFinalizeFilter(unseenNotifFilter)
pipeline.addCollectionListener(collectionListener)
- scope.launch { trackUnseenNotificationsWhileUnlocked() }
- scope.launch { invalidateWhenUnseenSettingChanges() }
+ scope.launch { trackUnseenFilterSettingChanges() }
dumpManager.registerDumpable(this)
}
- private suspend fun trackUnseenNotificationsWhileUnlocked() {
- // Whether or not we're actively tracking unseen notifications to mark them as seen when
- // appropriate.
- val isTrackingUnseen: Flow<Boolean> =
- keyguardRepository.isKeyguardShowing
- // transformLatest so that we can cancel listening to keyguard transitions once
- // isKeyguardShowing changes (after a successful transition to the keyguard).
- .transformLatest { isShowing ->
- if (isShowing) {
- // If the keyguard is showing, we're not tracking unseen.
- emit(false)
- } else {
- // If the keyguard stops showing, then start tracking unseen notifications.
- emit(true)
- // If the screen is turning off, stop tracking, but if that transition is
- // cancelled, then start again.
- emitAll(
- keyguardTransitionRepository.transitions.map { step ->
- !step.isScreenTurningOff
- }
- )
- }
- }
- // Prevent double emit of `false` caused by transition to AOD, followed by keyguard
- // showing
+ private suspend fun trackSeenNotifications() {
+ // Whether or not keyguard is visible (or occluded).
+ val isKeyguardPresent: Flow<Boolean> =
+ keyguardTransitionRepository.transitions
+ .map { step -> step.to != KeyguardState.GONE }
.distinctUntilChanged()
.onEach { trackingUnseen -> logger.logTrackingUnseen(trackingUnseen) }
- // Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is
- // showing again
- var clearUnseenOnBeginTracking = false
- isTrackingUnseen.collectLatest { trackingUnseen ->
- if (!trackingUnseen) {
- // Wait for the user to spend enough time on the lock screen before clearing unseen
- // set when unlocked
- awaitTimeSpentNotDozing(SEEN_TIMEOUT)
- clearUnseenOnBeginTracking = true
- logger.logSeenOnLockscreen()
+ // Separately track seen notifications while the device is locked, applying once the device
+ // is unlocked.
+ val notificationsSeenWhileLocked = mutableSetOf<NotificationEntry>()
+
+ // Use [collectLatest] to cancel any running jobs when [trackingUnseen] changes.
+ isKeyguardPresent.collectLatest { isKeyguardPresent: Boolean ->
+ if (isKeyguardPresent) {
+ // Keyguard is not gone, notifications need to be visible for a certain threshold
+ // before being marked as seen
+ trackSeenNotificationsWhileLocked(notificationsSeenWhileLocked)
} else {
- if (clearUnseenOnBeginTracking) {
- clearUnseenOnBeginTracking = false
- logger.logAllMarkedSeenOnUnlock()
- unseenNotifications.clear()
+ // Mark all seen-while-locked notifications as seen for real.
+ if (notificationsSeenWhileLocked.isNotEmpty()) {
+ unseenNotifications.removeAll(notificationsSeenWhileLocked)
+ logger.logAllMarkedSeenOnUnlock(
+ seenCount = notificationsSeenWhileLocked.size,
+ remainingUnseenCount = unseenNotifications.size
+ )
+ notificationsSeenWhileLocked.clear()
}
unseenNotifFilter.invalidateList("keyguard no longer showing")
- trackUnseenNotifications()
+ // Keyguard is gone, notifications can be immediately marked as seen when they
+ // become visible.
+ trackSeenNotificationsWhileUnlocked()
}
}
}
- private suspend fun awaitTimeSpentNotDozing(duration: Duration) {
- keyguardRepository.isDozing
- // Use transformLatest so that the timeout delay is cancelled if the device enters doze,
- // and is restarted when doze ends.
- .transformLatest { isDozing ->
- if (!isDozing) {
- delay(duration)
- // Signal timeout has completed
- emit(Unit)
+ /**
+ * Keep [notificationsSeenWhileLocked] updated to represent which notifications have actually
+ * been "seen" while the device is on the keyguard.
+ */
+ private suspend fun trackSeenNotificationsWhileLocked(
+ notificationsSeenWhileLocked: MutableSet<NotificationEntry>,
+ ) = coroutineScope {
+ // Remove removed notifications from the set
+ launch {
+ unseenEntryRemoved.collect { entry ->
+ if (notificationsSeenWhileLocked.remove(entry)) {
+ logger.logRemoveSeenOnLockscreen(entry)
}
}
- // Suspend until the first emission
- .first()
+ }
+ // Use collectLatest so that the timeout delay is cancelled if the device enters doze, and
+ // is restarted when doze ends.
+ keyguardRepository.isDozing.collectLatest { isDozing ->
+ if (!isDozing) {
+ trackSeenNotificationsWhileLockedAndNotDozing(notificationsSeenWhileLocked)
+ }
+ }
}
- // Track "unseen" notifications, marking them as seen when either shade is expanded or the
+ /**
+ * Keep [notificationsSeenWhileLocked] updated to represent which notifications have actually
+ * been "seen" while the device is on the keyguard and not dozing. Any new and existing unseen
+ * notifications are not marked as seen until they are visible for the [SEEN_TIMEOUT] duration.
+ */
+ private suspend fun trackSeenNotificationsWhileLockedAndNotDozing(
+ notificationsSeenWhileLocked: MutableSet<NotificationEntry>
+ ) = coroutineScope {
+ // All child tracking jobs will be cancelled automatically when this is cancelled.
+ val trackingJobsByEntry = mutableMapOf<NotificationEntry, Job>()
+
+ /**
+ * Wait for the user to spend enough time on the lock screen before removing notification
+ * from unseen set upon unlock.
+ */
+ suspend fun trackSeenDurationThreshold(entry: NotificationEntry) {
+ if (notificationsSeenWhileLocked.remove(entry)) {
+ logger.logResetSeenOnLockscreen(entry)
+ }
+ delay(SEEN_TIMEOUT)
+ notificationsSeenWhileLocked.add(entry)
+ trackingJobsByEntry.remove(entry)
+ logger.logSeenOnLockscreen(entry)
+ }
+
+ /** Stop any unseen tracking when a notification is removed. */
+ suspend fun stopTrackingRemovedNotifs(): Nothing =
+ unseenEntryRemoved.collect { entry ->
+ trackingJobsByEntry.remove(entry)?.let {
+ it.cancel()
+ logger.logStopTrackingLockscreenSeenDuration(entry)
+ }
+ }
+
+ /** Start tracking new notifications when they are posted. */
+ suspend fun trackNewUnseenNotifs(): Nothing = coroutineScope {
+ unseenEntryAdded.collect { entry ->
+ logger.logTrackingLockscreenSeenDuration(entry)
+ // If this is an update, reset the tracking.
+ trackingJobsByEntry[entry]?.let {
+ it.cancel()
+ logger.logResetSeenOnLockscreen(entry)
+ }
+ trackingJobsByEntry[entry] = launch { trackSeenDurationThreshold(entry) }
+ }
+ }
+
+ // Start tracking for all notifications that are currently unseen.
+ logger.logTrackingLockscreenSeenDuration(unseenNotifications)
+ unseenNotifications.forEach { entry ->
+ trackingJobsByEntry[entry] = launch { trackSeenDurationThreshold(entry) }
+ }
+
+ launch { trackNewUnseenNotifs() }
+ launch { stopTrackingRemovedNotifs() }
+ }
+
+ // Track "seen" notifications, marking them as such when either shade is expanded or the
// notification becomes heads up.
- private suspend fun trackUnseenNotifications() {
+ private suspend fun trackSeenNotificationsWhileUnlocked() {
coroutineScope {
launch { clearUnseenNotificationsWhenShadeIsExpanded() }
launch { markHeadsUpNotificationsAsSeen() }
@@ -212,7 +260,7 @@
}
}
- private suspend fun invalidateWhenUnseenSettingChanges() {
+ private suspend fun trackUnseenFilterSettingChanges() {
secureSettings
// emit whenever the setting has changed
.observerFlow(
@@ -228,17 +276,23 @@
UserHandle.USER_CURRENT,
) == 1
}
+ // don't emit anything if nothing has changed
+ .distinctUntilChanged()
// perform lookups on the bg thread pool
.flowOn(bgDispatcher)
// only track the most recent emission, if events are happening faster than they can be
// consumed
.conflate()
- // update local field and invalidate if necessary
- .collect { setting ->
+ .collectLatest { setting ->
+ // update local field and invalidate if necessary
if (setting != unseenFilterEnabled) {
unseenFilterEnabled = setting
unseenNotifFilter.invalidateList("unseen setting changed")
}
+ // if the setting is enabled, then start tracking and filtering unseen notifications
+ if (setting) {
+ trackSeenNotifications()
+ }
}
}
@@ -250,6 +304,7 @@
) {
logger.logUnseenAdded(entry.key)
unseenNotifications.add(entry)
+ unseenEntryAdded.tryEmit(entry)
}
}
@@ -259,12 +314,14 @@
) {
logger.logUnseenUpdated(entry.key)
unseenNotifications.add(entry)
+ unseenEntryAdded.tryEmit(entry)
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
if (unseenNotifications.remove(entry)) {
logger.logUnseenRemoved(entry.key)
+ unseenEntryRemoved.tryEmit(entry)
}
}
}
@@ -347,6 +404,3 @@
private val SEEN_TIMEOUT = 5.seconds
}
}
-
-private val TransitionStep.isScreenTurningOff: Boolean
- get() = transitionState == TransitionState.STARTED && to != KeyguardState.GONE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
index 4c33524..788659e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -19,6 +19,7 @@
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.UnseenNotificationLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
import javax.inject.Inject
private const val TAG = "KeyguardCoordinator"
@@ -28,11 +29,14 @@
constructor(
@UnseenNotificationLog private val buffer: LogBuffer,
) {
- fun logSeenOnLockscreen() =
+ fun logSeenOnLockscreen(entry: NotificationEntry) =
buffer.log(
TAG,
LogLevel.DEBUG,
- "Notifications on lockscreen will be marked as seen when unlocked."
+ messageInitializer = { str1 = entry.key },
+ messagePrinter = {
+ "Notification [$str1] on lockscreen will be marked as seen when unlocked."
+ },
)
fun logTrackingUnseen(trackingUnseen: Boolean) =
@@ -43,11 +47,21 @@
messagePrinter = { "${if (bool1) "Start" else "Stop"} tracking unseen notifications." },
)
- fun logAllMarkedSeenOnUnlock() =
+ fun logAllMarkedSeenOnUnlock(
+ seenCount: Int,
+ remainingUnseenCount: Int,
+ ) =
buffer.log(
TAG,
LogLevel.DEBUG,
- "Notifications have been marked as seen now that device is unlocked."
+ messageInitializer = {
+ int1 = seenCount
+ int2 = remainingUnseenCount
+ },
+ messagePrinter = {
+ "$int1 Notifications have been marked as seen now that device is unlocked. " +
+ "$int2 notifications remain unseen."
+ },
)
fun logShadeExpanded() =
@@ -96,4 +110,60 @@
messageInitializer = { str1 = key },
messagePrinter = { "Unseen notif has become heads up: $str1" },
)
+
+ fun logTrackingLockscreenSeenDuration(unseenNotifications: Set<NotificationEntry>) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = {
+ str1 = unseenNotifications.joinToString { it.key }
+ int1 = unseenNotifications.size
+ },
+ messagePrinter = {
+ "Tracking $int1 unseen notifications for lockscreen seen duration threshold: $str1"
+ },
+ )
+ }
+
+ fun logTrackingLockscreenSeenDuration(entry: NotificationEntry) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = entry.key },
+ messagePrinter = {
+ "Tracking new notification for lockscreen seen duration threshold: $str1"
+ },
+ )
+ }
+
+ fun logStopTrackingLockscreenSeenDuration(entry: NotificationEntry) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = entry.key },
+ messagePrinter = {
+ "Stop tracking removed notification for lockscreen seen duration threshold: $str1"
+ },
+ )
+ }
+
+ fun logResetSeenOnLockscreen(entry: NotificationEntry) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = entry.key },
+ messagePrinter = {
+ "Reset tracking updated notification for lockscreen seen duration threshold: $str1"
+ },
+ )
+ }
+
+ fun logRemoveSeenOnLockscreen(entry: NotificationEntry) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = entry.key },
+ messagePrinter = { "Notification marked as seen on lockscreen removed: $str1" },
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactory.kt
new file mode 100644
index 0000000..4429939
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactory.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.util.AttributeSet
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.notification.row.NotificationRowModule.NOTIF_REMOTEVIEWS_FACTORIES
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.withIncreasedIndent
+import java.io.PrintWriter
+import javax.inject.Inject
+import javax.inject.Named
+
+/**
+ * Implementation of [NotifLayoutInflaterFactory]. This class uses a set of
+ * [NotifRemoteViewsFactory] objects to create replacement views for Notification RemoteViews.
+ */
+open class NotifLayoutInflaterFactory
+@Inject
+constructor(
+ dumpManager: DumpManager,
+ @Named(NOTIF_REMOTEVIEWS_FACTORIES)
+ private val remoteViewsFactories: Set<@JvmSuppressWildcards NotifRemoteViewsFactory>
+) : LayoutInflater.Factory2, Dumpable {
+ init {
+ dumpManager.registerNormalDumpable(TAG, this)
+ }
+
+ override fun onCreateView(
+ parent: View?,
+ name: String,
+ context: Context,
+ attrs: AttributeSet
+ ): View? {
+ var view: View? = null
+ var handledFactory: NotifRemoteViewsFactory? = null
+ for (layoutFactory in remoteViewsFactories) {
+ view = layoutFactory.instantiate(parent, name, context, attrs)
+ if (view != null) {
+ check(handledFactory == null) {
+ "${layoutFactory.javaClass.name} tries to produce view. However, " +
+ "${handledFactory?.javaClass?.name} produced view for $name before."
+ }
+ handledFactory = layoutFactory
+ }
+ }
+ logOnCreateView(name, view, handledFactory)
+ return view
+ }
+
+ override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? =
+ onCreateView(null, name, context, attrs)
+
+ override fun dump(pw: PrintWriter, args: Array<out String>) {
+ val indentingPW = pw.asIndenting()
+
+ indentingPW.appendLine("$TAG ReplacementFactories:")
+ indentingPW.withIncreasedIndent {
+ remoteViewsFactories.forEach { indentingPW.appendLine(it.javaClass.simpleName) }
+ }
+ }
+
+ private fun logOnCreateView(
+ name: String,
+ replacedView: View?,
+ factory: NotifRemoteViewsFactory?
+ ) {
+ if (SPEW && replacedView != null && factory != null) {
+ Log.d(TAG, "$factory produced view for $name: $replacedView")
+ }
+ }
+
+ private companion object {
+ private const val TAG = "NotifLayoutInflaterFac"
+ private val SPEW = Log.isLoggable(TAG, Log.VERBOSE)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactory.kt
new file mode 100644
index 0000000..eebd4d4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactory.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+
+/** Interface used to create replacement view instances in Notification RemoteViews. */
+interface NotifRemoteViewsFactory {
+
+ /** return the replacement view instance for the given view name */
+ fun instantiate(parent: View?, name: String, context: Context, attrs: AttributeSet): View?
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 13d1978..0ad77bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -79,6 +79,7 @@
private final ConversationNotificationProcessor mConversationProcessor;
private final Executor mBgExecutor;
private final SmartReplyStateInflater mSmartReplyStateInflater;
+ private final NotifLayoutInflaterFactory mNotifLayoutInflaterFactory;
@Inject
NotificationContentInflater(
@@ -87,13 +88,15 @@
ConversationNotificationProcessor conversationProcessor,
MediaFeatureFlag mediaFeatureFlag,
@Background Executor bgExecutor,
- SmartReplyStateInflater smartRepliesInflater) {
+ SmartReplyStateInflater smartRepliesInflater,
+ NotifLayoutInflaterFactory notifLayoutInflaterFactory) {
mRemoteViewCache = remoteViewCache;
mRemoteInputManager = remoteInputManager;
mConversationProcessor = conversationProcessor;
mIsMediaInQS = mediaFeatureFlag.getEnabled();
mBgExecutor = bgExecutor;
mSmartReplyStateInflater = smartRepliesInflater;
+ mNotifLayoutInflaterFactory = notifLayoutInflaterFactory;
}
@Override
@@ -137,7 +140,8 @@
callback,
mRemoteInputManager.getRemoteViewsOnClickHandler(),
mIsMediaInQS,
- mSmartReplyStateInflater);
+ mSmartReplyStateInflater,
+ mNotifLayoutInflaterFactory);
if (mInflateSynchronously) {
task.onPostExecute(task.doInBackground());
} else {
@@ -160,7 +164,8 @@
bindParams.isLowPriority,
bindParams.usesIncreasedHeight,
bindParams.usesIncreasedHeadsUpHeight,
- packageContext);
+ packageContext,
+ mNotifLayoutInflaterFactory);
result = inflateSmartReplyViews(result, reInflateFlags, entry,
row.getContext(), packageContext,
@@ -298,7 +303,8 @@
private static InflationProgress createRemoteViews(@InflationFlag int reInflateFlags,
Notification.Builder builder, boolean isLowPriority, boolean usesIncreasedHeight,
- boolean usesIncreasedHeadsUpHeight, Context packageContext) {
+ boolean usesIncreasedHeadsUpHeight, Context packageContext,
+ NotifLayoutInflaterFactory notifLayoutInflaterFactory) {
InflationProgress result = new InflationProgress();
if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
@@ -316,7 +322,7 @@
if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
result.newPublicView = builder.makePublicContentView(isLowPriority);
}
-
+ setNotifsViewsInflaterFactory(result, notifLayoutInflaterFactory);
result.packageContext = packageContext;
result.headsUpStatusBarText = builder.getHeadsUpStatusBarText(false /* showingPublic */);
result.headsUpStatusBarTextPublic = builder.getHeadsUpStatusBarText(
@@ -324,6 +330,22 @@
return result;
}
+ private static void setNotifsViewsInflaterFactory(InflationProgress result,
+ NotifLayoutInflaterFactory notifLayoutInflaterFactory) {
+ setRemoteViewsInflaterFactory(result.newContentView, notifLayoutInflaterFactory);
+ setRemoteViewsInflaterFactory(result.newExpandedView,
+ notifLayoutInflaterFactory);
+ setRemoteViewsInflaterFactory(result.newHeadsUpView, notifLayoutInflaterFactory);
+ setRemoteViewsInflaterFactory(result.newPublicView, notifLayoutInflaterFactory);
+ }
+
+ private static void setRemoteViewsInflaterFactory(RemoteViews remoteViews,
+ NotifLayoutInflaterFactory notifLayoutInflaterFactory) {
+ if (remoteViews != null) {
+ remoteViews.setLayoutInflaterFactory(notifLayoutInflaterFactory);
+ }
+ }
+
private static CancellationSignal apply(
Executor bgExecutor,
boolean inflateSynchronously,
@@ -348,7 +370,6 @@
public void setResultView(View v) {
result.inflatedContentView = v;
}
-
@Override
public RemoteViews getRemoteView() {
return result.newContentView;
@@ -356,7 +377,7 @@
};
applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
- privateLayout, privateLayout.getContractedChild(),
+ privateLayout, privateLayout.getContractedChild(),
privateLayout.getVisibleWrapper(
NotificationContentView.VISIBLE_TYPE_CONTRACTED),
runningInflations, applyCallback);
@@ -758,8 +779,8 @@
* @param oldView The old view that was applied to the existing view before
* @return {@code true} if the RemoteViews are the same and the view can be reused to reapply.
*/
- @VisibleForTesting
- static boolean canReapplyRemoteView(final RemoteViews newView,
+ @VisibleForTesting
+ static boolean canReapplyRemoteView(final RemoteViews newView,
final RemoteViews oldView) {
return (newView == null && oldView == null) ||
(newView != null && oldView != null
@@ -800,6 +821,7 @@
private final ConversationNotificationProcessor mConversationProcessor;
private final boolean mIsMediaInQS;
private final SmartReplyStateInflater mSmartRepliesInflater;
+ private final NotifLayoutInflaterFactory mNotifLayoutInflaterFactory;
private AsyncInflationTask(
Executor bgExecutor,
@@ -815,7 +837,8 @@
InflationCallback callback,
RemoteViews.InteractionHandler remoteViewClickHandler,
boolean isMediaFlagEnabled,
- SmartReplyStateInflater smartRepliesInflater) {
+ SmartReplyStateInflater smartRepliesInflater,
+ NotifLayoutInflaterFactory notifLayoutInflaterFactory) {
mEntry = entry;
mRow = row;
mBgExecutor = bgExecutor;
@@ -831,6 +854,7 @@
mCallback = callback;
mConversationProcessor = conversationProcessor;
mIsMediaInQS = isMediaFlagEnabled;
+ mNotifLayoutInflaterFactory = notifLayoutInflaterFactory;
entry.setInflationTask(this);
}
@@ -874,7 +898,8 @@
}
InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
- mUsesIncreasedHeadsUpHeight, packageContext);
+ mUsesIncreasedHeadsUpHeight, packageContext,
+ mNotifLayoutInflaterFactory);
InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
InflationProgress result = inflateSmartReplyViews(
inflationProgress,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
index 111b575..b2a3780 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -17,15 +17,26 @@
package com.android.systemui.statusbar.notification.row;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
import dagger.Binds;
import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Named;
/**
* Dagger Module containing notification row and view inflation implementations.
*/
@Module
public abstract class NotificationRowModule {
+ public static final String NOTIF_REMOTEVIEWS_FACTORIES =
+ "notif_remoteviews_factories";
+
/**
* Provides notification row content binder instance.
*/
@@ -41,4 +52,15 @@
@SysUISingleton
public abstract NotifRemoteViewCache provideNotifRemoteViewCache(
NotifRemoteViewCacheImpl cacheImpl);
+
+ /** Provides view factories to be inflated in notification content. */
+ @Provides
+ @ElementsIntoSet
+ @Named(NOTIF_REMOTEVIEWS_FACTORIES)
+ static Set<NotifRemoteViewsFactory> provideNotifRemoteViewsFactories(
+ FeatureFlags featureFlags
+ ) {
+ final Set<NotifRemoteViewsFactory> replacementFactories = new HashSet<>();
+ return replacementFactories;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 479fbdb..8063c8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -5919,7 +5919,17 @@
Trace.beginSection("NSSL.resetAllSwipeState()");
mSwipeHelper.resetTouchState();
for (int i = 0; i < getChildCount(); i++) {
- mSwipeHelper.forceResetSwipeState(getChildAt(i));
+ View child = getChildAt(i);
+ mSwipeHelper.forceResetSwipeState(child);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow childRow = (ExpandableNotificationRow) child;
+ List<ExpandableNotificationRow> grandchildren = childRow.getAttachedChildren();
+ if (grandchildren != null) {
+ for (ExpandableNotificationRow grandchild : grandchildren) {
+ mSwipeHelper.forceResetSwipeState(grandchild);
+ }
+ }
+ }
}
updateContinuousShadowDrawing();
Trace.endSection();
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 0d3dfae..278ae95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -42,6 +42,7 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.IWallpaperManager;
import android.app.KeyguardManager;
import android.app.Notification;
@@ -1612,7 +1613,6 @@
// (Right now, there's a circular dependency.)
mNotificationShadeWindowController.setWindowRootView(windowRootView);
mNotificationShadeWindowViewController.setupExpandedStatusBar();
- mShadeController.setShadeViewController(mShadeSurface);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
mBackActionInteractor.setup(mQsController, mShadeSurface);
@@ -1773,7 +1773,10 @@
EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
sbn.getKey());
wakeUpForFullScreenIntent();
- notification.fullScreenIntent.send();
+ ActivityOptions opts = ActivityOptions.makeBasic();
+ opts.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ notification.fullScreenIntent.send(opts.toBundle());
entry.notifyFullScreenIntentLaunched();
} catch (PendingIntent.CanceledException e) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 2fd244e..0fde3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -239,7 +239,7 @@
private void reloadDimens(Context context) {
Resources res = context.getResources();
- mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+ mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size_sp);
mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin);
mAodIconAppearTranslation = res.getDimensionPixelSize(
R.dimen.shelf_appear_translation);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index bef422c..418f920 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -339,6 +339,7 @@
}
}
if (child instanceof StatusBarIconView) {
+ ((StatusBarIconView) child).updateIconDimens();
((StatusBarIconView) child).setDozing(mDozing, false, 0);
}
}
@@ -447,9 +448,14 @@
@VisibleForTesting
boolean isOverflowing(boolean isLastChild, float translationX, float layoutEnd,
float iconSize) {
- // Layout end, as used here, does not include padding end.
- final float overflowX = isLastChild ? layoutEnd : layoutEnd - iconSize;
- return translationX >= overflowX;
+ if (isLastChild) {
+ return translationX + iconSize > layoutEnd;
+ } else {
+ // If the child is not the last child, we need to ensure that we have room for the next
+ // icon and the dot. The dot could be as large as an icon, so verify that we have room
+ // for 2 icons.
+ return translationX + iconSize * 2f > layoutEnd;
+ }
}
/**
@@ -489,10 +495,7 @@
// First icon to overflow.
if (firstOverflowIndex == -1 && isOverflowing) {
firstOverflowIndex = i;
- mVisualOverflowStart = layoutEnd - mIconSize;
- if (forceOverflow || mIsStaticLayout) {
- mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
- }
+ mVisualOverflowStart = translationX;
}
final float drawingScale = mOnLockScreen && view instanceof StatusBarIconView
? ((StatusBarIconView) view).getIconScaleIncreased()
@@ -537,9 +540,10 @@
IconState iconState = mIconStates.get(mIsolatedIcon);
if (iconState != null) {
// Most of the time the icon isn't yet added when this is called but only happening
- // later
- iconState.setXTranslation(mIsolatedIconLocation.left - mAbsolutePosition[0]
- - (1 - mIsolatedIcon.getIconScale()) * mIsolatedIcon.getWidth() / 2.0f);
+ // later. The isolated icon position left should equal to the mIsolatedIconLocation
+ // to ensure the icon be put at the center of the HUN icon placeholder,
+ // {@See HeadsUpAppearanceController#updateIsolatedIconLocation}.
+ iconState.setXTranslation(mIsolatedIconLocation.left - mAbsolutePosition[0]);
iconState.visibleState = StatusBarIconView.STATE_ICON;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index c16e13c..e4e912e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -52,6 +52,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.animation.ShadeInterpolation;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
@@ -59,7 +60,6 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.ScrimAlpha;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -1492,6 +1492,13 @@
mColors.setSupportsDarkText(
ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5);
}
+
+ int surface = Utils.getColorAttr(mScrimBehind.getContext(),
+ com.android.internal.R.attr.materialColorSurface).getDefaultColor();
+ for (ScrimState state : ScrimState.values()) {
+ state.setSurfaceColor(surface);
+ }
+
mNeedsDrawableColorUpdate = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 7b20283..e3b65ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -122,11 +122,19 @@
@Override
public void prepare(ScrimState previousState) {
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
- mBehindTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
+ mBehindTint = mClipQsScrim ? Color.BLACK : mSurfaceColor;
mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
mNotifTint = Color.TRANSPARENT;
mFrontAlpha = 0f;
}
+
+ @Override
+ public void setSurfaceColor(int surfaceColor) {
+ super.setSurfaceColor(surfaceColor);
+ if (!mClipQsScrim) {
+ mBehindTint = mSurfaceColor;
+ }
+ }
},
/**
@@ -295,6 +303,7 @@
int mFrontTint = Color.TRANSPARENT;
int mBehindTint = Color.TRANSPARENT;
int mNotifTint = Color.TRANSPARENT;
+ int mSurfaceColor = Color.TRANSPARENT;
boolean mAnimateChange = true;
float mAodFrontScrimAlpha;
@@ -409,6 +418,10 @@
mDefaultScrimAlpha = defaultScrimAlpha;
}
+ public void setSurfaceColor(int surfaceColor) {
+ mSurfaceColor = surfaceColor;
+ }
+
public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
mWallpaperSupportsAmbientMode = wallpaperSupportsAmbientMode;
}
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 b14fe90..59583dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -370,7 +370,7 @@
private final MobileIconsViewModel mMobileIconsViewModel;
protected final Context mContext;
- protected final int mIconSize;
+ protected int mIconSize;
// Whether or not these icons show up in dumpsys
protected boolean mShouldLog = false;
private StatusBarIconController mController;
@@ -395,10 +395,10 @@
mStatusBarPipelineFlags = statusBarPipelineFlags;
mMobileContextProvider = mobileContextProvider;
mContext = group.getContext();
- mIconSize = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_icon_size);
mLocation = location;
+ reloadDimens();
+
if (statusBarPipelineFlags.runNewMobileIconsBackend()) {
// This starts the flow for the new pipeline, and will notify us of changes if
// {@link StatusBarPipelineFlags#useNewMobileIcons} is also true.
@@ -609,13 +609,9 @@
mGroup.removeAllViews();
}
- protected void onDensityOrFontScaleChanged() {
- for (int i = 0; i < mGroup.getChildCount(); i++) {
- View child = mGroup.getChildAt(i);
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
- child.setLayoutParams(lp);
- }
+ protected void reloadDimens() {
+ mIconSize = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_icon_size_sp);
}
private void setHeightAndCenter(ImageView imageView, int height) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 3a18423..80d5651 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -109,6 +109,7 @@
}
group.setController(this);
+ group.reloadDimens();
mIconGroups.add(group);
List<Slot> allSlots = mStatusBarIconList.getSlots();
for (int i = 0; i < allSlots.size(); i++) {
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 cb2a78d..5c1dfbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -51,6 +51,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -306,6 +307,16 @@
@Nullable private TaskbarDelegate mTaskbarDelegate;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onTrustGrantedForCurrentUser(
+ boolean dismissKeyguard,
+ boolean newlyUnlocked,
+ @NonNull TrustGrantFlags flags,
+ @Nullable String message
+ ) {
+ updateAlternateBouncerShowing(mAlternateBouncerInteractor.maybeHide());
+ }
+
@Override
public void onEmergencyCallAction() {
// Since we won't get a setOccluded call we have to reset the view manually such that
@@ -431,7 +442,6 @@
mDockManager.addListener(mDockEventListener);
mIsDocked = mDockManager.isDocked();
}
- mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
}
/** Register a callback, to be invoked by the Predictive Back system. */
@@ -1570,14 +1580,6 @@
|| mode == KeyguardSecurityModel.SecurityMode.SimPuk;
}
- private KeyguardStateController.Callback mKeyguardStateControllerCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onUnlockedChanged() {
- updateAlternateBouncerShowing(mAlternateBouncerInteractor.maybeHide());
- }
- };
-
/**
* Delegate used to send show and hide events to an alternate authentication method instead of
* the regular pin/pattern/password bouncer.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 604b1f5..d83664f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -22,6 +22,8 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -73,13 +75,16 @@
// Any ignored icon will never be added as a child
private ArrayList<String> mIgnoredSlots = new ArrayList<>();
+ private Configuration mConfiguration;
+
public StatusIconContainer(Context context) {
this(context, null);
}
public StatusIconContainer(Context context, AttributeSet attrs) {
super(context, attrs);
- initDimens();
+ mConfiguration = new Configuration(context.getResources().getConfiguration());
+ reloadDimens();
setWillNotDraw(!DEBUG_OVERFLOW);
}
@@ -100,10 +105,10 @@
return mShouldRestrictIcons;
}
- private void initDimens() {
+ private void reloadDimens() {
// This is the same value that StatusBarIconView uses
mIconDotFrameWidth = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_icon_size);
+ com.android.internal.R.dimen.status_bar_icon_size_sp);
mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);
mIconSpacing = getResources().getDimensionPixelSize(R.dimen.status_bar_system_icon_spacing);
int radius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
@@ -233,6 +238,16 @@
child.setTag(R.id.status_bar_view_state_tag, null);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ final int configDiff = newConfig.diff(mConfiguration);
+ mConfiguration.setTo(newConfig);
+ if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
+ reloadDimens();
+ }
+ }
+
/**
* Add a name of an icon slot to be ignored. It will not show up nor be measured
* @param slotName name of the icon as it exists in
@@ -342,13 +357,17 @@
int totalVisible = mLayoutStates.size();
int maxVisible = totalVisible <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;
- mUnderflowStart = 0;
+ // Init mUnderflowStart value with the offset to let the dot be placed next to battery icon.
+ // This is to prevent if the underflow happens at rightest(totalVisible - 1) child then
+ // break the for loop with mUnderflowStart staying 0(initial value), causing the dot be
+ // placed at the leftest side.
+ mUnderflowStart = (int) Math.max(contentStart, width - getPaddingEnd() - mUnderflowWidth);
int visible = 0;
int firstUnderflowIndex = -1;
for (int i = totalVisible - 1; i >= 0; i--) {
StatusIconState state = mLayoutStates.get(i);
// Allow room for underflow if we found we need it in onMeasure
- if (mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth))
+ if ((mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth)))
|| (mShouldRestrictIcons && (visible >= maxVisible))) {
firstUnderflowIndex = i;
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
index 1a13404..8373854 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt
@@ -118,7 +118,7 @@
it.visibleState = STATE_DOT
}
- val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size)
+ val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size_sp)
val lp = LayoutParams(width, width)
lp.gravity = Gravity.CENTER_VERTICAL or Gravity.START
addView(dotView, lp)
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 4e52be9..7f35dfb 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
@@ -34,6 +34,7 @@
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.log.table.logDiffsForTable
@@ -48,6 +49,7 @@
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import java.util.concurrent.Executor
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
@@ -60,7 +62,9 @@
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
/** Real implementation of [WifiRepository]. */
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@@ -76,8 +80,9 @@
logger: WifiInputLogger,
@WifiTableLog wifiTableLogBuffer: TableLogBuffer,
@Main mainExecutor: Executor,
+ @Background private val bgDispatcher: CoroutineDispatcher,
@Application scope: CoroutineScope,
- wifiManager: WifiManager,
+ private val wifiManager: WifiManager,
) : RealWifiRepository {
private val wifiStateChangeEvents: Flow<Unit> =
@@ -93,20 +98,25 @@
// have changed.
override val isWifiEnabled: StateFlow<Boolean> =
merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
- .mapLatest { wifiManager.isWifiEnabled }
+ .onStart { emit(Unit) }
+ .mapLatest { isWifiEnabled() }
.distinctUntilChanged()
.logDiffsForTable(
wifiTableLogBuffer,
columnPrefix = "",
columnName = "isEnabled",
- initialValue = wifiManager.isWifiEnabled,
+ initialValue = false,
)
.stateIn(
scope = scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = wifiManager.isWifiEnabled,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
)
+ // [WifiManager.isWifiEnabled] is a blocking IPC call, so fetch it in the background.
+ private suspend fun isWifiEnabled(): Boolean =
+ withContext(bgDispatcher) { wifiManager.isWifiEnabled }
+
override val isWifiDefault: StateFlow<Boolean> =
connectivityRepository.defaultConnections
// TODO(b/274493701): Should wifi be considered default if it's carrier merged?
@@ -289,6 +299,7 @@
private val logger: WifiInputLogger,
@WifiTableLog private val wifiTableLogBuffer: TableLogBuffer,
@Main private val mainExecutor: Executor,
+ @Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
) {
fun create(wifiManager: WifiManager): WifiRepositoryImpl {
@@ -299,6 +310,7 @@
logger,
wifiTableLogBuffer,
mainExecutor,
+ bgDispatcher,
scope,
wifiManager,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 6875b52..f994372 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -374,6 +374,13 @@
@Override
public void onDensityOrFontScaleChanged() {
+ reloadDimens();
+ }
+
+ private void reloadDimens() {
+ // reset mCachedWidth so the new width would be updated properly when next onMeasure
+ mCachedWidth = -1;
+
FontSizeUtils.updateFontSize(this, R.dimen.status_bar_clock_size);
setPaddingRelative(
mContext.getResources().getDimensionPixelSize(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index 22b4c9d..736b145 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy
+import android.app.ActivityOptions
import android.app.Notification
import android.app.PendingIntent
import android.app.RemoteInput
@@ -275,7 +276,10 @@
entry.sbn.instanceId)
try {
- pendingIntent.send(view.context, 0, intent)
+ val options = ActivityOptions.makeBasic()
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ pendingIntent.send(view.context, 0, intent, null, null, null, options.toBundle())
} catch (e: PendingIntent.CanceledException) {
Log.i(TAG, "Unable to send remote input result", e)
uiEventLogger.logWithInstanceId(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
index cac5e32..1776e5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy
+import android.app.ActivityOptions
import android.app.Notification
import android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY
import android.app.PendingIntent
@@ -491,7 +492,11 @@
entry.setHasSentReply()
try {
val intent = createRemoteInputIntent(smartReplies, choice)
- smartReplies.pendingIntent.send(context, 0, intent)
+ val opts = ActivityOptions.makeBasic()
+ opts.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
+ smartReplies.pendingIntent.send(context, 0, intent, /* onFinished */null,
+ /* handler */ null, /* requiredPermission */ null, opts.toBundle())
} catch (e: PendingIntent.CanceledException) {
Log.w(TAG, "Unable to send smart reply", e)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
index 3362097..fd7c30f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java
@@ -103,6 +103,8 @@
if (mPendingIntent != null) {
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
+ options.setPendingIntentBackgroundActivityStartMode(
+ BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
mPendingIntent.send(options.toBundle());
}
} catch (PendingIntent.CanceledException e) {
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 4a9921e..bcf3b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -240,10 +240,8 @@
Insets.of(0, safeTouchRegionHeight, 0, 0));
}
lp.providedInsets = new InsetsFrameProvider[] {
- new InsetsFrameProvider(mInsetsSourceOwner, 0, statusBars())
- .setInsetsSize(Insets.of(0, height, 0, 0)),
- new InsetsFrameProvider(mInsetsSourceOwner, 0, tappableElement())
- .setInsetsSize(Insets.of(0, height, 0, 0)),
+ new InsetsFrameProvider(mInsetsSourceOwner, 0, statusBars()),
+ new InsetsFrameProvider(mInsetsSourceOwner, 0, tappableElement()),
gestureInsetsProvider
};
return lp;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 3f31ff94..8cf71a0 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -45,7 +45,7 @@
import com.android.systemui.settings.dagger.MultiUserUtilsModule;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
import com.android.systemui.shade.ShadeController;
-import com.android.systemui.shade.ShadeControllerImpl;
+import com.android.systemui.shade.ShadeControllerEmptyImpl;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyboardShortcutsModule;
@@ -140,7 +140,7 @@
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
- abstract ShadeController provideShadeController(ShadeControllerImpl shadeController);
+ abstract ShadeController provideShadeController(ShadeControllerEmptyImpl shadeController);
@SysUISingleton
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index a487f53..4d506f0 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -27,6 +27,7 @@
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
+import android.os.Process
import android.os.RemoteException
import android.os.UserHandle
import android.os.UserManager
@@ -334,6 +335,7 @@
onBroadcastReceived(intent, previousSelectedUser)
}
.launchIn(applicationScope)
+ restartSecondaryService(repository.getSelectedUserInfo().id)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
}
@@ -530,6 +532,12 @@
}
}
+ /** Returns the ID of the currently-selected user. */
+ @UserIdInt
+ fun getSelectedUserId(): Int {
+ return repository.getSelectedUserInfo().id
+ }
+
private fun showDialog(request: ShowDialogRequestModel) {
_dialogShowRequests.value = request
}
@@ -646,7 +654,7 @@
// Connect to the new secondary user's service (purely to ensure that a persistent
// SystemUI application is created for that user)
- if (userId != UserHandle.USER_SYSTEM) {
+ if (userId != Process.myUserHandle().identifier) {
applicationContext.startServiceAsUser(
intent,
UserHandle.of(userId),
@@ -772,17 +780,16 @@
}
// TODO(b/246631653): cache the bitmaps to avoid the background work to fetch them.
- val userIcon = withContext(backgroundDispatcher) {
- manager.getUserIcon(userId)
- ?.let { bitmap ->
+ val userIcon =
+ withContext(backgroundDispatcher) {
+ manager.getUserIcon(userId)?.let { bitmap ->
val iconSize =
- applicationContext
- .resources
- .getDimensionPixelSize(R.dimen.bouncer_user_switcher_icon_size)
+ applicationContext.resources.getDimensionPixelSize(
+ R.dimen.bouncer_user_switcher_icon_size
+ )
Icon.scaleDownIfNecessary(bitmap, iconSize, iconSize)
}
- }
-
+ }
if (userIcon != null) {
return BitmapDrawable(userIcon)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 2318988..b67f280 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -18,7 +18,8 @@
import android.content.BroadcastReceiver
import android.testing.AndroidTestingRunner
import android.view.View
-import android.widget.TextView
+import android.view.ViewTreeObserver
+import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
@@ -83,7 +84,13 @@
@Mock private lateinit var bgExecutor: Executor
@Mock private lateinit var featureFlags: FeatureFlags
@Mock private lateinit var smallClockController: ClockFaceController
+ @Mock private lateinit var smallClockView: View
+ @Mock private lateinit var smallClockViewTreeObserver: ViewTreeObserver
+ @Mock private lateinit var smallClockFrame: FrameLayout
+ @Mock private lateinit var smallClockFrameViewTreeObserver: ViewTreeObserver
@Mock private lateinit var largeClockController: ClockFaceController
+ @Mock private lateinit var largeClockView: View
+ @Mock private lateinit var largeClockViewTreeObserver: ViewTreeObserver
@Mock private lateinit var smallClockEvents: ClockFaceEvents
@Mock private lateinit var largeClockEvents: ClockFaceEvents
@Mock private lateinit var parentView: View
@@ -99,8 +106,12 @@
fun setUp() {
whenever(clock.smallClock).thenReturn(smallClockController)
whenever(clock.largeClock).thenReturn(largeClockController)
- whenever(smallClockController.view).thenReturn(TextView(context))
- whenever(largeClockController.view).thenReturn(TextView(context))
+ whenever(smallClockController.view).thenReturn(smallClockView)
+ whenever(smallClockView.parent).thenReturn(smallClockFrame)
+ whenever(smallClockView.viewTreeObserver).thenReturn(smallClockViewTreeObserver)
+ whenever(smallClockFrame.viewTreeObserver).thenReturn(smallClockFrameViewTreeObserver)
+ whenever(largeClockController.view).thenReturn(largeClockView)
+ whenever(largeClockView.viewTreeObserver).thenReturn(largeClockViewTreeObserver)
whenever(smallClockController.events).thenReturn(smallClockEvents)
whenever(largeClockController.events).thenReturn(largeClockEvents)
whenever(clock.events).thenReturn(events)
@@ -302,8 +313,38 @@
verify(configurationController).removeCallback(any())
verify(batteryController).removeCallback(any())
verify(keyguardUpdateMonitor).removeCallback(any())
+ verify(smallClockController.view)
+ .removeOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
+ verify(largeClockController.view)
+ .removeOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
}
+ @Test
+ fun registerOnAttachStateChangeListener_validate() = runBlocking(IMMEDIATE) {
+ verify(smallClockController.view)
+ .addOnAttachStateChangeListener(underTest.smallClockOnAttachStateChangeListener)
+ verify(largeClockController.view)
+ .addOnAttachStateChangeListener(underTest.largeClockOnAttachStateChangeListener)
+ }
+
+ @Test
+ fun registerAndRemoveOnGlobalLayoutListener_correctly() = runBlocking(IMMEDIATE) {
+ underTest.smallClockOnAttachStateChangeListener!!.onViewAttachedToWindow(smallClockView)
+ verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
+ underTest.smallClockOnAttachStateChangeListener!!.onViewDetachedFromWindow(smallClockView)
+ verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
+ }
+
+ @Test
+ fun registerOnGlobalLayoutListener_RemoveOnAttachStateChangeListener_correctly() =
+ runBlocking(IMMEDIATE) {
+ underTest.smallClockOnAttachStateChangeListener!!
+ .onViewAttachedToWindow(smallClockView)
+ verify(smallClockFrame.viewTreeObserver).addOnGlobalLayoutListener(any())
+ underTest.unregisterListeners()
+ verify(smallClockFrame.viewTreeObserver).removeOnGlobalLayoutListener(any())
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
new file mode 100644
index 0000000..ac04bc4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerBaseTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import static android.view.View.INVISIBLE;
+
+import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.log.LogBuffer;
+import com.android.systemui.plugins.ClockAnimations;
+import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.ClockEvents;
+import com.android.systemui.plugins.ClockFaceConfig;
+import com.android.systemui.plugins.ClockFaceController;
+import com.android.systemui.plugins.ClockFaceEvents;
+import com.android.systemui.plugins.ClockTickRate;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.clocks.AnimatableClockView;
+import com.android.systemui.shared.clocks.ClockRegistry;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
+import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.NotificationIconContainer;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {
+
+ @Mock
+ protected KeyguardClockSwitch mView;
+ @Mock
+ protected StatusBarStateController mStatusBarStateController;
+ @Mock
+ protected ClockRegistry mClockRegistry;
+ @Mock
+ KeyguardSliceViewController mKeyguardSliceViewController;
+ @Mock
+ NotificationIconAreaController mNotificationIconAreaController;
+ @Mock
+ LockscreenSmartspaceController mSmartspaceController;
+
+ @Mock
+ Resources mResources;
+ @Mock
+ KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock
+ protected ClockController mClockController;
+ @Mock
+ protected ClockFaceController mLargeClockController;
+ @Mock
+ protected ClockFaceController mSmallClockController;
+ @Mock
+ protected ClockAnimations mClockAnimations;
+ @Mock
+ protected ClockEvents mClockEvents;
+ @Mock
+ protected ClockFaceEvents mClockFaceEvents;
+ @Mock
+ DumpManager mDumpManager;
+ @Mock
+ ClockEventController mClockEventController;
+
+ @Mock
+ protected NotificationIconContainer mNotificationIcons;
+ @Mock
+ protected AnimatableClockView mSmallClockView;
+ @Mock
+ protected AnimatableClockView mLargeClockView;
+ @Mock
+ protected FrameLayout mSmallClockFrame;
+ @Mock
+ protected FrameLayout mLargeClockFrame;
+ @Mock
+ protected SecureSettings mSecureSettings;
+ @Mock
+ protected LogBuffer mLogBuffer;
+
+ protected final View mFakeDateView = (View) (new ViewGroup(mContext) {
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {}
+ });
+ protected final View mFakeWeatherView = new View(mContext);
+ protected final View mFakeSmartspaceView = new View(mContext);
+
+ protected KeyguardClockSwitchController mController;
+ protected View mSliceView;
+ protected LinearLayout mStatusArea;
+ protected FakeExecutor mExecutor;
+ protected FakeFeatureFlags mFakeFeatureFlags;
+ @Captor protected ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mView.findViewById(R.id.left_aligned_notification_icon_container))
+ .thenReturn(mNotificationIcons);
+ when(mNotificationIcons.getLayoutParams()).thenReturn(
+ mock(RelativeLayout.LayoutParams.class));
+ when(mView.getContext()).thenReturn(getContext());
+ when(mView.getResources()).thenReturn(mResources);
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
+ .thenReturn(100);
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin))
+ .thenReturn(-200);
+ when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
+ .thenReturn(INVISIBLE);
+
+ when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
+ when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
+ when(mSmallClockView.getContext()).thenReturn(getContext());
+ when(mLargeClockView.getContext()).thenReturn(getContext());
+
+ when(mView.isAttachedToWindow()).thenReturn(true);
+ when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
+ when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
+ when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
+ mExecutor = new FakeExecutor(new FakeSystemClock());
+ mFakeFeatureFlags = new FakeFeatureFlags();
+ mFakeFeatureFlags.set(FACE_AUTH_REFACTOR, false);
+ mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
+ mController = new KeyguardClockSwitchController(
+ mView,
+ mStatusBarStateController,
+ mClockRegistry,
+ mKeyguardSliceViewController,
+ mNotificationIconAreaController,
+ mSmartspaceController,
+ mKeyguardUnlockAnimationController,
+ mSecureSettings,
+ mExecutor,
+ mDumpManager,
+ mClockEventController,
+ mLogBuffer,
+ KeyguardInteractorFactory.create(mFakeFeatureFlags).getKeyguardInteractor(),
+ mFakeFeatureFlags
+ );
+
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+ when(mLargeClockController.getView()).thenReturn(mLargeClockView);
+ when(mSmallClockController.getView()).thenReturn(mSmallClockView);
+ when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
+ when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
+ when(mClockController.getEvents()).thenReturn(mClockEvents);
+ when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
+ when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
+ when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
+ when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
+ when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
+ when(mClockEventController.getClock()).thenReturn(mClockController);
+ when(mSmallClockController.getConfig())
+ .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
+ when(mLargeClockController.getConfig())
+ .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
+
+ mSliceView = new View(getContext());
+ when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
+ mStatusArea = new LinearLayout(getContext());
+ when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
+ }
+
+ protected void init() {
+ mController.init();
+
+ verify(mView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture());
+ mAttachCaptor.getValue().onViewAttachedToWindow(mView);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 9e561ed..e64ef04 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -21,186 +21,33 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.log.LogBuffer;
-import com.android.systemui.plugins.ClockAnimations;
-import com.android.systemui.plugins.ClockController;
-import com.android.systemui.plugins.ClockEvents;
import com.android.systemui.plugins.ClockFaceConfig;
-import com.android.systemui.plugins.ClockFaceController;
-import com.android.systemui.plugins.ClockFaceEvents;
import com.android.systemui.plugins.ClockTickRate;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.NotificationIconContainer;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.settings.SecureSettings;
-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;
import org.mockito.verification.VerificationMode;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
-
- @Mock
- private KeyguardClockSwitch mView;
- @Mock
- private StatusBarStateController mStatusBarStateController;
- @Mock
- private ClockRegistry mClockRegistry;
- @Mock
- KeyguardSliceViewController mKeyguardSliceViewController;
- @Mock
- NotificationIconAreaController mNotificationIconAreaController;
- @Mock
- LockscreenSmartspaceController mSmartspaceController;
-
- @Mock
- Resources mResources;
- @Mock
- KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
- @Mock
- private ClockController mClockController;
- @Mock
- private ClockFaceController mLargeClockController;
- @Mock
- private ClockFaceController mSmallClockController;
- @Mock
- private ClockAnimations mClockAnimations;
- @Mock
- private ClockEvents mClockEvents;
- @Mock
- private ClockFaceEvents mClockFaceEvents;
- @Mock
- DumpManager mDumpManager;
- @Mock
- ClockEventController mClockEventController;
-
- @Mock
- private NotificationIconContainer mNotificationIcons;
- @Mock
- private AnimatableClockView mSmallClockView;
- @Mock
- private AnimatableClockView mLargeClockView;
- @Mock
- private FrameLayout mSmallClockFrame;
- @Mock
- private FrameLayout mLargeClockFrame;
- @Mock
- private SecureSettings mSecureSettings;
- @Mock
- private LogBuffer mLogBuffer;
-
- private final View mFakeDateView = (View) (new ViewGroup(mContext) {
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {}
- });
- private final View mFakeWeatherView = new View(mContext);
- private final View mFakeSmartspaceView = new View(mContext);
-
- private KeyguardClockSwitchController mController;
- private View mSliceView;
- private FakeExecutor mExecutor;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
-
- when(mView.findViewById(R.id.left_aligned_notification_icon_container))
- .thenReturn(mNotificationIcons);
- when(mNotificationIcons.getLayoutParams()).thenReturn(
- mock(RelativeLayout.LayoutParams.class));
- when(mView.getContext()).thenReturn(getContext());
- when(mView.getResources()).thenReturn(mResources);
- when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
- .thenReturn(100);
- when(mResources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin))
- .thenReturn(-200);
- when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
- .thenReturn(View.INVISIBLE);
-
- when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
- when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
- when(mSmallClockView.getContext()).thenReturn(getContext());
- when(mLargeClockView.getContext()).thenReturn(getContext());
-
- when(mView.isAttachedToWindow()).thenReturn(true);
- when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
- when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
- when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
- mExecutor = new FakeExecutor(new FakeSystemClock());
- mController = new KeyguardClockSwitchController(
- mView,
- mStatusBarStateController,
- mClockRegistry,
- mKeyguardSliceViewController,
- mNotificationIconAreaController,
- mSmartspaceController,
- mKeyguardUnlockAnimationController,
- mSecureSettings,
- mExecutor,
- mDumpManager,
- mClockEventController,
- mLogBuffer
- );
-
- when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
- when(mLargeClockController.getView()).thenReturn(mLargeClockView);
- when(mSmallClockController.getView()).thenReturn(mSmallClockView);
- when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
- when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
- when(mClockController.getEvents()).thenReturn(mClockEvents);
- when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
- when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
- when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
- when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
- when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
- when(mClockEventController.getClock()).thenReturn(mClockController);
- when(mSmallClockController.getConfig())
- .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
- when(mLargeClockController.getConfig())
- .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false));
-
- mSliceView = new View(getContext());
- when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
- when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(
- new LinearLayout(getContext()));
- }
-
+public class KeyguardClockSwitchControllerTest extends KeyguardClockSwitchControllerBaseTest {
@Test
public void testInit_viewAlreadyAttached() {
mController.init();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt
new file mode 100644
index 0000000..9a1a4e2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerWithCoroutinesTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class KeyguardClockSwitchControllerWithCoroutinesTest : KeyguardClockSwitchControllerBaseTest() {
+
+ @Test
+ fun testStatusAreaVisibility_onLockscreenHostedDreamStateChanged() =
+ runBlocking(IMMEDIATE) {
+ // GIVEN starting state for the keyguard clock and wallpaper dream enabled
+ mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
+ init()
+
+ // WHEN dreaming starts
+ mController.mIsActiveDreamLockscreenHostedCallback.accept(
+ true /* isActiveDreamLockscreenHosted */
+ )
+
+ // THEN the status area is hidden
+ mExecutor.runAllReady()
+ assertEquals(View.INVISIBLE, mStatusArea.visibility)
+
+ // WHEN dreaming stops
+ mController.mIsActiveDreamLockscreenHostedCallback.accept(
+ false /* isActiveDreamLockscreenHosted */
+ )
+ mExecutor.runAllReady()
+
+ // THEN status area view is visible
+ assertEquals(View.VISIBLE, mStatusArea.visibility)
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 2eea9eb..5d75428 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -32,15 +32,18 @@
import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -78,6 +81,9 @@
private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
private lateinit var fakeFeatureFlags: FakeFeatureFlags
+ @Captor
+ lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -107,7 +113,7 @@
}
@Test
- fun tabletopPostureIsDetectedFromStart() {
+ fun onViewAttached_deviceHalfFolded_propagatedToPatternView() {
overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f)
whenever(mPostureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
@@ -116,6 +122,26 @@
assertThat(getPatternTopGuideline()).isEqualTo(getExpectedTopGuideline())
}
+ @Test
+ fun onDevicePostureChanged_deviceOpened_propagatedToPatternView() {
+ overrideResource(R.dimen.half_opened_bouncer_height_ratio, 0.5f)
+ whenever(mPostureController.devicePosture)
+ .thenReturn(DEVICE_POSTURE_HALF_OPENED)
+
+ mKeyguardPatternViewController.onViewAttached()
+
+ // Verify view begins in posture state DEVICE_POSTURE_HALF_OPENED
+ assertThat(getPatternTopGuideline()).isEqualTo(getExpectedTopGuideline())
+
+ // Simulate posture change to state DEVICE_POSTURE_OPENED with callback
+ verify(mPostureController).addCallback(postureCallbackCaptor.capture())
+ val postureCallback: DevicePostureController.Callback = postureCallbackCaptor.value
+ postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED)
+
+ // Verify view is now in posture state DEVICE_POSTURE_OPENED
+ assertThat(getPatternTopGuideline()).isNotEqualTo(getExpectedTopGuideline())
+ }
+
private fun getPatternTopGuideline(): Float {
val cs = ConstraintSet()
val container =
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index d3b4190..9db267c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -30,12 +30,16 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.policy.DevicePostureController
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED
+import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.any
@@ -79,7 +83,9 @@
@Mock lateinit var deleteButton: NumPadButton
@Mock lateinit var enterButton: View
- lateinit var pinViewController: KeyguardPinViewController
+ private lateinit var pinViewController: KeyguardPinViewController
+
+ @Captor lateinit var postureCallbackCaptor: ArgumentCaptor<DevicePostureController.Callback>
@Before
fun setup() {
@@ -97,6 +103,9 @@
`when`(keyguardPinView.findViewById<NumPadButton>(R.id.delete_button))
.thenReturn(deleteButton)
`when`(keyguardPinView.findViewById<View>(R.id.key_enter)).thenReturn(enterButton)
+ // For posture tests:
+ `when`(keyguardPinView.buttons).thenReturn(arrayOf())
+
pinViewController =
KeyguardPinViewController(
keyguardPinView,
@@ -115,6 +124,33 @@
}
@Test
+ fun onViewAttached_deviceHalfFolded_propagatedToPinView() {
+ `when`(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
+
+ pinViewController.onViewAttached()
+
+ verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED)
+ }
+
+ @Test
+ fun onDevicePostureChanged_deviceHalfFolded_propagatedToPinView() {
+ `when`(postureController.devicePosture).thenReturn(DEVICE_POSTURE_HALF_OPENED)
+
+ // Verify view begins in posture state DEVICE_POSTURE_HALF_OPENED
+ pinViewController.onViewAttached()
+
+ verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_HALF_OPENED)
+
+ // Simulate posture change to state DEVICE_POSTURE_OPENED with callback
+ verify(postureController).addCallback(postureCallbackCaptor.capture())
+ val postureCallback: DevicePostureController.Callback = postureCallbackCaptor.value
+ postureCallback.onPostureChanged(DEVICE_POSTURE_OPENED)
+
+ // Verify view is now in posture state DEVICE_POSTURE_OPENED
+ verify(keyguardPinView).onDevicePostureChanged(DEVICE_POSTURE_OPENED)
+ }
+
+ @Test
fun startAppearAnimation() {
pinViewController.startAppearAnimation()
verify(keyguardMessageAreaController)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
deleted file mode 100644
index 58b1edc..0000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ /dev/null
@@ -1,732 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT;
-import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
-import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.hardware.biometrics.BiometricOverlayConstants;
-import android.media.AudioManager;
-import android.telephony.TelephonyManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableResources;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.WindowInsetsController;
-import android.widget.FrameLayout;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.biometrics.SideFpsController;
-import com.android.systemui.biometrics.SideFpsUiRequestSource;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.classifier.FalsingA11yDelegate;
-import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
-import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
-import com.android.systemui.log.SessionTracker;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.util.settings.GlobalSettings;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
-public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
- private static final int TARGET_USER_ID = 100;
- @Rule
- public MockitoRule mRule = MockitoJUnit.rule();
- @Mock
- private KeyguardSecurityContainer mView;
- @Mock
- private AdminSecondaryLockScreenController.Factory mAdminSecondaryLockScreenControllerFactory;
- @Mock
- private AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
- @Mock
- private LockPatternUtils mLockPatternUtils;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private KeyguardSecurityModel mKeyguardSecurityModel;
- @Mock
- private MetricsLogger mMetricsLogger;
- @Mock
- private UiEventLogger mUiEventLogger;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- private KeyguardInputViewController mInputViewController;
- @Mock
- private WindowInsetsController mWindowInsetsController;
- @Mock
- private KeyguardSecurityViewFlipper mSecurityViewFlipper;
- @Mock
- private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
- @Mock
- private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory;
- @Mock
- private KeyguardMessageAreaController mKeyguardMessageAreaController;
- @Mock
- private BouncerKeyguardMessageArea mKeyguardMessageArea;
- @Mock
- private ConfigurationController mConfigurationController;
- @Mock
- private EmergencyButtonController mEmergencyButtonController;
- @Mock
- private FalsingCollector mFalsingCollector;
- @Mock
- private FalsingManager mFalsingManager;
- @Mock
- private GlobalSettings mGlobalSettings;
- @Mock
- private FeatureFlags mFeatureFlags;
- @Mock
- private UserSwitcherController mUserSwitcherController;
- @Mock
- private SessionTracker mSessionTracker;
- @Mock
- private KeyguardViewController mKeyguardViewController;
- @Mock
- private SideFpsController mSideFpsController;
- @Mock
- private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock;
- @Mock
- private FalsingA11yDelegate mFalsingA11yDelegate;
- @Mock
- private TelephonyManager mTelephonyManager;
- @Mock
- private ViewMediatorCallback mViewMediatorCallback;
- @Mock
- private AudioManager mAudioManager;
-
- @Captor
- private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
- @Captor
- private ArgumentCaptor<KeyguardSecurityContainer.SwipeListener> mSwipeListenerArgumentCaptor;
-
- @Captor
- private ArgumentCaptor<KeyguardSecurityViewFlipperController.OnViewInflatedCallback>
- mOnViewInflatedCallbackArgumentCaptor;
-
- private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
- private KeyguardPasswordViewController mKeyguardPasswordViewController;
- private KeyguardPasswordView mKeyguardPasswordView;
- private TestableResources mTestableResources;
-
- @Before
- public void setup() {
- mTestableResources = mContext.getOrCreateTestableResources();
- mTestableResources.getResources().getConfiguration().orientation =
- Configuration.ORIENTATION_UNDEFINED;
-
- when(mView.getContext()).thenReturn(mContext);
- when(mView.getResources()).thenReturn(mTestableResources.getResources());
- FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(/* width= */ 0, /* height= */
- 0);
- lp.gravity = 0;
- when(mView.getLayoutParams()).thenReturn(lp);
- when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
- .thenReturn(mAdminSecondaryLockScreenController);
- when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
- mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate(
- R.layout.keyguard_password_view, null));
- when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper);
- when(mKeyguardPasswordView.requireViewById(R.id.bouncer_message_area))
- .thenReturn(mKeyguardMessageArea);
- when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
- .thenReturn(mKeyguardMessageAreaController);
- when(mKeyguardPasswordView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
- when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(SecurityMode.PIN);
- when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
- FakeFeatureFlags featureFlags = new FakeFeatureFlags();
- featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true);
-
- mKeyguardPasswordViewController = new KeyguardPasswordViewController(
- (KeyguardPasswordView) mKeyguardPasswordView, mKeyguardUpdateMonitor,
- SecurityMode.Password, mLockPatternUtils, null,
- mKeyguardMessageAreaControllerFactory, null, null, mEmergencyButtonController,
- null, mock(Resources.class), null, mKeyguardViewController,
- featureFlags);
-
- mKeyguardSecurityContainerController = new KeyguardSecurityContainerController(
- mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
- mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
- mKeyguardStateController, mKeyguardSecurityViewFlipperController,
- mConfigurationController, mFalsingCollector, mFalsingManager,
- mUserSwitcherController, mFeatureFlags, mGlobalSettings,
- mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate,
- mTelephonyManager, mViewMediatorCallback, mAudioManager,
- mock(KeyguardFaceAuthInteractor.class),
- mock(BouncerMessageInteractor.class));
- }
-
- @Test
- public void onInitConfiguresViewMode() {
- mKeyguardSecurityContainerController.onInit();
- verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
- eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
- eq(mFalsingA11yDelegate));
- }
-
- @Test
- public void showSecurityScreen_canInflateAllModes() {
- SecurityMode[] modes = SecurityMode.values();
- for (SecurityMode mode : modes) {
- when(mInputViewController.getSecurityMode()).thenReturn(mode);
- mKeyguardSecurityContainerController.showSecurityScreen(mode);
- if (mode == SecurityMode.Invalid) {
- verify(mKeyguardSecurityViewFlipperController, never()).getSecurityView(
- any(SecurityMode.class), any(KeyguardSecurityCallback.class), any(
- KeyguardSecurityViewFlipperController.OnViewInflatedCallback.class)
- );
- } else {
- verify(mKeyguardSecurityViewFlipperController).getSecurityView(
- eq(mode), any(KeyguardSecurityCallback.class), any(
- KeyguardSecurityViewFlipperController.OnViewInflatedCallback.class)
- );
- }
- }
- }
-
- @Test
- public void onResourcesUpdate_callsThroughOnRotationChange() {
- clearInvocations(mView);
-
- // Rotation is the same, shouldn't cause an update
- mKeyguardSecurityContainerController.updateResources();
- verify(mView, never()).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
- eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
- eq(mFalsingA11yDelegate));
-
- // Update rotation. Should trigger update
- mTestableResources.getResources().getConfiguration().orientation =
- Configuration.ORIENTATION_LANDSCAPE;
-
- mKeyguardSecurityContainerController.updateResources();
- verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
- eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
- eq(mFalsingA11yDelegate));
- }
-
- private void touchDown() {
- mKeyguardSecurityContainerController.mGlobalTouchListener.onTouchEvent(
- MotionEvent.obtain(
- /* downTime= */0,
- /* eventTime= */0,
- MotionEvent.ACTION_DOWN,
- /* x= */0,
- /* y= */0,
- /* metaState= */0));
- }
-
- @Test
- public void onInterceptTap_inhibitsFalsingInSidedSecurityMode() {
-
- when(mView.isTouchOnTheOtherSideOfSecurity(any())).thenReturn(false);
- touchDown();
- verify(mFalsingCollector, never()).avoidGesture();
-
- when(mView.isTouchOnTheOtherSideOfSecurity(any())).thenReturn(true);
- touchDown();
- verify(mFalsingCollector).avoidGesture();
- }
-
- @Test
- public void showSecurityScreen_oneHandedMode_flagDisabled_noOneHandedMode() {
- mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, false);
- setupGetSecurityView(SecurityMode.Pattern);
-
- mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
- verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
- eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
- eq(mFalsingA11yDelegate));
- }
-
- @Test
- public void showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode() {
- mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
- setupGetSecurityView(SecurityMode.Pattern);
- verify(mView).initMode(eq(MODE_ONE_HANDED), eq(mGlobalSettings), eq(mFalsingManager),
- eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
- eq(mFalsingA11yDelegate));
- }
-
- @Test
- public void showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() {
- mTestableResources.addOverride(R.bool.can_use_one_handed_bouncer, true);
- setupGetSecurityView(SecurityMode.Password);
-
- verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
- eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
- eq(mFalsingA11yDelegate));
- }
-
- @Test
- public void addUserSwitcherCallback() {
- ArgumentCaptor<KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback>
- captor = ArgumentCaptor.forClass(
- KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class);
- setupGetSecurityView(SecurityMode.Password);
-
- verify(mView).initMode(anyInt(), any(GlobalSettings.class), any(FalsingManager.class),
- any(UserSwitcherController.class),
- captor.capture(),
- eq(mFalsingA11yDelegate));
- captor.getValue().showUnlockToContinueMessage();
- getViewControllerImmediately();
- verify(mKeyguardPasswordViewControllerMock).showMessage(
- /* message= */ getContext().getString(R.string.keyguard_unlock_to_continue),
- /* colorState= */ null,
- /* animated= */ true);
- }
-
- @Test
- public void addUserSwitchCallback() {
- mKeyguardSecurityContainerController.onViewAttached();
- verify(mUserSwitcherController)
- .addUserSwitchCallback(any(UserSwitcherController.UserSwitchCallback.class));
- mKeyguardSecurityContainerController.onViewDetached();
- verify(mUserSwitcherController)
- .removeUserSwitchCallback(any(UserSwitcherController.UserSwitchCallback.class));
- }
-
- @Test
- public void onBouncerVisibilityChanged_resetsScale() {
- mKeyguardSecurityContainerController.onBouncerVisibilityChanged(false);
- verify(mView).resetScale();
- }
-
- @Test
- public void showNextSecurityScreenOrFinish_setsSecurityScreenToPinAfterSimPinUnlock() {
- // GIVEN the current security method is SimPin
- when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
- when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false);
- mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin);
-
- // WHEN a request is made from the SimPin screens to show the next security method
- when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.PIN);
- mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
- /* authenticated= */true,
- TARGET_USER_ID,
- /* bypassSecondaryLockScreen= */true,
- SecurityMode.SimPin);
-
- // THEN the next security method of PIN is set, and the keyguard is not marked as done
-
- verify(mViewMediatorCallback, never()).keyguardDonePending(anyBoolean(), anyInt());
- verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
- assertThat(mKeyguardSecurityContainerController.getCurrentSecurityMode())
- .isEqualTo(SecurityMode.PIN);
- }
-
- @Test
- public void showNextSecurityScreenOrFinish_DeviceNotSecure() {
- // GIVEN the current security method is SimPin
- when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
- when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false);
- mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin);
-
- // WHEN a request is made from the SimPin screens to show the next security method
- when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.None);
- when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true);
- mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
- /* authenticated= */true,
- TARGET_USER_ID,
- /* bypassSecondaryLockScreen= */true,
- SecurityMode.SimPin);
-
- // THEN the next security method of None will dismiss keyguard.
- verify(mViewMediatorCallback).keyguardDone(anyBoolean(), anyInt());
- }
-
- @Test
- public void showNextSecurityScreenOrFinish_ignoresCallWhenSecurityMethodHasChanged() {
- //GIVEN current security mode has been set to PIN
- mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.PIN);
-
- //WHEN a request comes from SimPin to dismiss the security screens
- boolean keyguardDone = mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
- /* authenticated= */true,
- TARGET_USER_ID,
- /* bypassSecondaryLockScreen= */true,
- SecurityMode.SimPin);
-
- //THEN no action has happened, which will not dismiss the security screens
- assertThat(keyguardDone).isEqualTo(false);
- verify(mKeyguardUpdateMonitor, never()).getUserHasTrust(anyInt());
- }
-
- @Test
- public void showNextSecurityScreenOrFinish_SimPin_Swipe() {
- // GIVEN the current security method is SimPin
- when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
- when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false);
- mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin);
-
- // WHEN a request is made from the SimPin screens to show the next security method
- when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.None);
- // WHEN security method is SWIPE
- when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false);
- mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
- /* authenticated= */true,
- TARGET_USER_ID,
- /* bypassSecondaryLockScreen= */true,
- SecurityMode.SimPin);
-
- // THEN the next security method of None will dismiss keyguard.
- verify(mViewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt());
- }
-
-
- @Test
- public void onSwipeUp_whenFaceDetectionIsNotRunning_initiatesFaceAuth() {
- KeyguardSecurityContainer.SwipeListener registeredSwipeListener =
- getRegisteredSwipeListener();
- when(mKeyguardUpdateMonitor.isFaceDetectionRunning()).thenReturn(false);
- setupGetSecurityView(SecurityMode.Password);
-
- registeredSwipeListener.onSwipeUp();
-
- verify(mKeyguardUpdateMonitor).requestFaceAuth(
- FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER);
- }
-
- @Test
- public void onSwipeUp_whenFaceDetectionIsRunning_doesNotInitiateFaceAuth() {
- KeyguardSecurityContainer.SwipeListener registeredSwipeListener =
- getRegisteredSwipeListener();
- when(mKeyguardUpdateMonitor.isFaceDetectionRunning()).thenReturn(true);
-
- registeredSwipeListener.onSwipeUp();
-
- verify(mKeyguardUpdateMonitor, never())
- .requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER);
- }
-
- @Test
- public void onSwipeUp_whenFaceDetectionIsTriggered_hidesBouncerMessage() {
- KeyguardSecurityContainer.SwipeListener registeredSwipeListener =
- getRegisteredSwipeListener();
- when(mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER))
- .thenReturn(true);
- setupGetSecurityView(SecurityMode.Password);
-
- clearInvocations(mKeyguardSecurityViewFlipperController);
- registeredSwipeListener.onSwipeUp();
- getViewControllerImmediately();
-
- verify(mKeyguardPasswordViewControllerMock).showMessage(/* message= */
- null, /* colorState= */ null, /* animated= */ true);
- }
-
- @Test
- public void onSwipeUp_whenFaceDetectionIsNotTriggered_retainsBouncerMessage() {
- KeyguardSecurityContainer.SwipeListener registeredSwipeListener =
- getRegisteredSwipeListener();
- when(mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER))
- .thenReturn(false);
- setupGetSecurityView(SecurityMode.Password);
-
- registeredSwipeListener.onSwipeUp();
-
- verify(mKeyguardPasswordViewControllerMock, never()).showMessage(/* message= */
- null, /* colorState= */ null, /* animated= */ true);
- }
-
- @Test
- public void onDensityOrFontScaleChanged() {
- ArgumentCaptor<ConfigurationController.ConfigurationListener>
- configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
- ConfigurationController.ConfigurationListener.class);
- mKeyguardSecurityContainerController.onViewAttached();
- verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
- clearInvocations(mKeyguardSecurityViewFlipperController);
-
- configurationListenerArgumentCaptor.getValue().onDensityOrFontScaleChanged();
-
- verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView(
- eq(SecurityMode.PIN),
- any(KeyguardSecurityCallback.class),
- mOnViewInflatedCallbackArgumentCaptor.capture());
-
- mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController);
-
- verify(mView).onDensityOrFontScaleChanged();
- }
-
- @Test
- public void onThemeChanged() {
- ArgumentCaptor<ConfigurationController.ConfigurationListener>
- configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
- ConfigurationController.ConfigurationListener.class);
- mKeyguardSecurityContainerController.onViewAttached();
- verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
- clearInvocations(mKeyguardSecurityViewFlipperController);
-
- configurationListenerArgumentCaptor.getValue().onThemeChanged();
-
- verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView(
- eq(SecurityMode.PIN),
- any(KeyguardSecurityCallback.class),
- mOnViewInflatedCallbackArgumentCaptor.capture());
-
- mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController);
-
- verify(mView).reset();
- verify(mKeyguardSecurityViewFlipperController).reset();
- verify(mView).reloadColors();
- }
-
- @Test
- public void onUiModeChanged() {
- ArgumentCaptor<ConfigurationController.ConfigurationListener>
- configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
- ConfigurationController.ConfigurationListener.class);
- mKeyguardSecurityContainerController.onViewAttached();
- verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
- clearInvocations(mKeyguardSecurityViewFlipperController);
-
- configurationListenerArgumentCaptor.getValue().onUiModeChanged();
-
- verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView(
- eq(SecurityMode.PIN),
- any(KeyguardSecurityCallback.class),
- mOnViewInflatedCallbackArgumentCaptor.capture());
-
- mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController);
-
- verify(mView).reloadColors();
- }
-
- @Test
- public void testHasDismissActions() {
- assertFalse("Action not set yet", mKeyguardSecurityContainerController.hasDismissActions());
- mKeyguardSecurityContainerController.setOnDismissAction(mock(
- ActivityStarter.OnDismissAction.class),
- null /* cancelAction */);
- assertTrue("Action should exist", mKeyguardSecurityContainerController.hasDismissActions());
- }
-
- @Test
- public void testWillRunDismissFromKeyguardIsTrue() {
- ActivityStarter.OnDismissAction action = mock(ActivityStarter.OnDismissAction.class);
- when(action.willRunAnimationOnKeyguard()).thenReturn(true);
- mKeyguardSecurityContainerController.setOnDismissAction(action, null /* cancelAction */);
-
- mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
-
- assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isTrue();
- }
-
- @Test
- public void testWillRunDismissFromKeyguardIsFalse() {
- ActivityStarter.OnDismissAction action = mock(ActivityStarter.OnDismissAction.class);
- when(action.willRunAnimationOnKeyguard()).thenReturn(false);
- mKeyguardSecurityContainerController.setOnDismissAction(action, null /* cancelAction */);
-
- mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
-
- assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isFalse();
- }
-
- @Test
- public void testWillRunDismissFromKeyguardIsFalseWhenNoDismissActionSet() {
- mKeyguardSecurityContainerController.setOnDismissAction(null /* action */,
- null /* cancelAction */);
-
- mKeyguardSecurityContainerController.finish(false /* strongAuth */, 0 /* currentUser */);
-
- assertThat(mKeyguardSecurityContainerController.willRunDismissFromKeyguard()).isFalse();
- }
-
- @Test
- public void testOnStartingToHide() {
- mKeyguardSecurityContainerController.onStartingToHide();
- verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
- any(KeyguardSecurityCallback.class),
- mOnViewInflatedCallbackArgumentCaptor.capture());
-
- mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(mInputViewController);
- verify(mInputViewController).onStartingToHide();
- }
-
- @Test
- public void testGravityReappliedOnConfigurationChange() {
- // Set initial gravity
- mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
- Gravity.CENTER);
- mTestableResources.addOverride(
- R.bool.can_use_one_handed_bouncer, false);
-
- // Kick off the initial pass...
- mKeyguardSecurityContainerController.onInit();
- verify(mView).setLayoutParams(any());
- clearInvocations(mView);
-
- // Now simulate a config change
- mTestableResources.addOverride(R.integer.keyguard_host_view_gravity,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
-
- mKeyguardSecurityContainerController.updateResources();
- verify(mView).setLayoutParams(any());
- }
-
- @Test
- public void testGravityUsesOneHandGravityWhenApplicable() {
- mTestableResources.addOverride(
- R.integer.keyguard_host_view_gravity,
- Gravity.CENTER);
- mTestableResources.addOverride(
- R.integer.keyguard_host_view_one_handed_gravity,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
-
- // Start disabled.
- mTestableResources.addOverride(
- R.bool.can_use_one_handed_bouncer, false);
-
- mKeyguardSecurityContainerController.onInit();
- verify(mView).setLayoutParams(argThat(
- (ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
- argument.gravity == Gravity.CENTER));
- clearInvocations(mView);
-
- // And enable
- mTestableResources.addOverride(
- R.bool.can_use_one_handed_bouncer, true);
-
- mKeyguardSecurityContainerController.updateResources();
- verify(mView).setLayoutParams(argThat(
- (ArgumentMatcher<FrameLayout.LayoutParams>) argument ->
- argument.gravity == (Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM)));
- }
-
- @Test
- public void testUpdateKeyguardPositionDelegatesToSecurityContainer() {
- mKeyguardSecurityContainerController.updateKeyguardPosition(1.0f);
- verify(mView).updatePositionByTouchX(1.0f);
- }
-
- @Test
- public void testReinflateViewFlipper() {
- KeyguardSecurityViewFlipperController.OnViewInflatedCallback onViewInflatedCallback =
- controller -> {
- };
- mKeyguardSecurityContainerController.reinflateViewFlipper(onViewInflatedCallback);
- verify(mKeyguardSecurityViewFlipperController).clearViews();
- verify(mKeyguardSecurityViewFlipperController).asynchronouslyInflateView(
- any(SecurityMode.class),
- any(KeyguardSecurityCallback.class), eq(onViewInflatedCallback));
- }
-
- @Test
- public void testSideFpsControllerShow() {
- mKeyguardSecurityContainerController.updateSideFpsVisibility(/* isVisible= */ true);
- verify(mSideFpsController).show(
- SideFpsUiRequestSource.PRIMARY_BOUNCER,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD);
- }
-
- @Test
- public void testSideFpsControllerHide() {
- mKeyguardSecurityContainerController.updateSideFpsVisibility(/* isVisible= */ false);
- verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER);
- }
-
- @Test
- public void setExpansion_setsAlpha() {
- mKeyguardSecurityContainerController.setExpansion(EXPANSION_VISIBLE);
-
- verify(mView).setAlpha(1f);
- verify(mView).setTranslationY(0f);
- }
-
- private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
- mKeyguardSecurityContainerController.onViewAttached();
- verify(mView).setSwipeListener(mSwipeListenerArgumentCaptor.capture());
- return mSwipeListenerArgumentCaptor.getValue();
- }
-
- private void setupGetSecurityView(SecurityMode securityMode) {
- mKeyguardSecurityContainerController.showSecurityScreen(securityMode);
- getViewControllerImmediately();
- }
-
- private void getViewControllerImmediately() {
- verify(mKeyguardSecurityViewFlipperController, atLeastOnce()).getSecurityView(
- any(SecurityMode.class), any(),
- mOnViewInflatedCallbackArgumentCaptor.capture());
- mOnViewInflatedCallbackArgumentCaptor.getValue().onViewInflated(
- (KeyguardInputViewController) mKeyguardPasswordViewControllerMock);
-
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
new file mode 100644
index 0000000..d447174
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -0,0 +1,810 @@
+/*
+ * 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.
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.keyguard
+
+import android.content.res.Configuration
+import android.hardware.biometrics.BiometricOverlayConstants
+import android.media.AudioManager
+import android.telephony.TelephonyManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.testing.TestableResources
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.WindowInsetsController
+import android.widget.FrameLayout
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.widget.LockPatternUtils
+import com.android.keyguard.KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.SideFpsController
+import com.android.systemui.biometrics.SideFpsUiRequestSource
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
+import com.android.systemui.classifier.FalsingA11yDelegate
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.log.SessionTracker
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.util.kotlin.JavaAdapter
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argThat
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.settings.GlobalSettings
+import com.google.common.truth.Truth
+import java.util.Optional
+import junit.framework.Assert
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+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.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatcher
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
+
+ @Mock private lateinit var view: KeyguardSecurityContainer
+ @Mock
+ private lateinit var adminSecondaryLockScreenControllerFactory:
+ AdminSecondaryLockScreenController.Factory
+ @Mock
+ private lateinit var adminSecondaryLockScreenController: AdminSecondaryLockScreenController
+ @Mock private lateinit var lockPatternUtils: LockPatternUtils
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var keyguardSecurityModel: KeyguardSecurityModel
+ @Mock private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var uiEventLogger: UiEventLogger
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var inputViewController: KeyguardInputViewController<KeyguardInputView>
+ @Mock private lateinit var windowInsetsController: WindowInsetsController
+ @Mock private lateinit var securityViewFlipper: KeyguardSecurityViewFlipper
+ @Mock private lateinit var viewFlipperController: KeyguardSecurityViewFlipperController
+ @Mock private lateinit var messageAreaControllerFactory: KeyguardMessageAreaController.Factory
+ @Mock private lateinit var keyguardMessageAreaController: KeyguardMessageAreaController<*>
+ @Mock private lateinit var keyguardMessageArea: BouncerKeyguardMessageArea
+ @Mock private lateinit var configurationController: ConfigurationController
+ @Mock private lateinit var emergencyButtonController: EmergencyButtonController
+ @Mock private lateinit var falsingCollector: FalsingCollector
+ @Mock private lateinit var falsingManager: FalsingManager
+ @Mock private lateinit var globalSettings: GlobalSettings
+ @Mock private lateinit var userSwitcherController: UserSwitcherController
+ @Mock private lateinit var sessionTracker: SessionTracker
+ @Mock private lateinit var keyguardViewController: KeyguardViewController
+ @Mock private lateinit var sideFpsController: SideFpsController
+ @Mock private lateinit var keyguardPasswordViewControllerMock: KeyguardPasswordViewController
+ @Mock private lateinit var falsingA11yDelegate: FalsingA11yDelegate
+ @Mock private lateinit var telephonyManager: TelephonyManager
+ @Mock private lateinit var viewMediatorCallback: ViewMediatorCallback
+ @Mock private lateinit var audioManager: AudioManager
+ @Mock private lateinit var userInteractor: UserInteractor
+
+ @Captor
+ private lateinit var swipeListenerArgumentCaptor:
+ ArgumentCaptor<KeyguardSecurityContainer.SwipeListener>
+ @Captor
+ private lateinit var onViewInflatedCallbackArgumentCaptor:
+ ArgumentCaptor<KeyguardSecurityViewFlipperController.OnViewInflatedCallback>
+
+ private lateinit var featureFlags: FakeFeatureFlags
+ private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
+ private lateinit var keyguardPasswordView: KeyguardPasswordView
+ private lateinit var testableResources: TestableResources
+ private lateinit var sceneTestUtils: SceneTestUtils
+ private lateinit var sceneInteractor: SceneInteractor
+
+ private lateinit var underTest: KeyguardSecurityContainerController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ testableResources = mContext.getOrCreateTestableResources()
+ testableResources.resources.configuration.orientation = Configuration.ORIENTATION_UNDEFINED
+ whenever(view.context).thenReturn(mContext)
+ whenever(view.resources).thenReturn(testableResources.resources)
+
+ val lp = FrameLayout.LayoutParams(/* width= */ 0, /* height= */ 0)
+ lp.gravity = 0
+ whenever(view.layoutParams).thenReturn(lp)
+
+ whenever(adminSecondaryLockScreenControllerFactory.create(any()))
+ .thenReturn(adminSecondaryLockScreenController)
+ whenever(securityViewFlipper.windowInsetsController).thenReturn(windowInsetsController)
+ keyguardPasswordView =
+ spy(
+ LayoutInflater.from(mContext).inflate(R.layout.keyguard_password_view, null)
+ as KeyguardPasswordView
+ )
+ whenever(keyguardPasswordView.rootView).thenReturn(securityViewFlipper)
+ whenever<Any?>(keyguardPasswordView.requireViewById(R.id.bouncer_message_area))
+ .thenReturn(keyguardMessageArea)
+ whenever(messageAreaControllerFactory.create(any()))
+ .thenReturn(keyguardMessageAreaController)
+ whenever(keyguardPasswordView.windowInsetsController).thenReturn(windowInsetsController)
+ whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(SecurityMode.PIN)
+ whenever(keyguardStateController.canDismissLockScreen()).thenReturn(true)
+
+ featureFlags = FakeFeatureFlags()
+ featureFlags.set(Flags.REVAMPED_BOUNCER_MESSAGES, true)
+ featureFlags.set(Flags.SCENE_CONTAINER, false)
+ featureFlags.set(Flags.BOUNCER_USER_SWITCHER, false)
+
+ keyguardPasswordViewController =
+ KeyguardPasswordViewController(
+ keyguardPasswordView,
+ keyguardUpdateMonitor,
+ SecurityMode.Password,
+ lockPatternUtils,
+ null,
+ messageAreaControllerFactory,
+ null,
+ null,
+ emergencyButtonController,
+ null,
+ mock(),
+ null,
+ keyguardViewController,
+ featureFlags
+ )
+
+ whenever(userInteractor.getSelectedUserId()).thenReturn(TARGET_USER_ID)
+ sceneTestUtils = SceneTestUtils(this)
+ sceneInteractor = sceneTestUtils.sceneInteractor()
+
+ underTest =
+ KeyguardSecurityContainerController(
+ view,
+ adminSecondaryLockScreenControllerFactory,
+ lockPatternUtils,
+ keyguardUpdateMonitor,
+ keyguardSecurityModel,
+ metricsLogger,
+ uiEventLogger,
+ keyguardStateController,
+ viewFlipperController,
+ configurationController,
+ falsingCollector,
+ falsingManager,
+ userSwitcherController,
+ featureFlags,
+ globalSettings,
+ sessionTracker,
+ Optional.of(sideFpsController),
+ falsingA11yDelegate,
+ telephonyManager,
+ viewMediatorCallback,
+ audioManager,
+ mock(),
+ mock(),
+ { JavaAdapter(sceneTestUtils.testScope.backgroundScope) },
+ userInteractor,
+ ) {
+ sceneInteractor
+ }
+ }
+
+ @Test
+ fun onInitConfiguresViewMode() {
+ underTest.onInit()
+ verify(view)
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_DEFAULT),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+ }
+
+ @Test
+ fun showSecurityScreen_canInflateAllModes() {
+ val modes = SecurityMode.values()
+ for (mode in modes) {
+ whenever(inputViewController.securityMode).thenReturn(mode)
+ underTest.showSecurityScreen(mode)
+ if (mode == SecurityMode.Invalid) {
+ verify(viewFlipperController, never()).getSecurityView(any(), any(), any())
+ } else {
+ verify(viewFlipperController).getSecurityView(eq(mode), any(), any())
+ }
+ }
+ }
+
+ @Test
+ fun onResourcesUpdate_callsThroughOnRotationChange() {
+ clearInvocations(view)
+
+ // Rotation is the same, shouldn't cause an update
+ underTest.updateResources()
+ verify(view, never())
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_DEFAULT),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+
+ // Update rotation. Should trigger update
+ testableResources.resources.configuration.orientation = Configuration.ORIENTATION_LANDSCAPE
+ underTest.updateResources()
+ verify(view)
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_DEFAULT),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+ }
+
+ private fun touchDown() {
+ underTest.mGlobalTouchListener.onTouchEvent(
+ MotionEvent.obtain(
+ /* downTime= */ 0,
+ /* eventTime= */ 0,
+ MotionEvent.ACTION_DOWN,
+ /* x= */ 0f,
+ /* y= */ 0f,
+ /* metaState= */ 0
+ )
+ )
+ }
+
+ @Test
+ fun onInterceptTap_inhibitsFalsingInSidedSecurityMode() {
+ whenever(view.isTouchOnTheOtherSideOfSecurity(any())).thenReturn(false)
+ touchDown()
+ verify(falsingCollector, never()).avoidGesture()
+ whenever(view.isTouchOnTheOtherSideOfSecurity(any())).thenReturn(true)
+ touchDown()
+ verify(falsingCollector).avoidGesture()
+ }
+
+ @Test
+ fun showSecurityScreen_oneHandedMode_flagDisabled_noOneHandedMode() {
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, false)
+ setupGetSecurityView(SecurityMode.Pattern)
+ underTest.showSecurityScreen(SecurityMode.Pattern)
+ verify(view)
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_DEFAULT),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+ }
+
+ @Test
+ fun showSecurityScreen_oneHandedMode_flagEnabled_oneHandedMode() {
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, true)
+ setupGetSecurityView(SecurityMode.Pattern)
+ verify(view)
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_ONE_HANDED),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+ }
+
+ @Test
+ fun showSecurityScreen_twoHandedMode_flagEnabled_noOneHandedMode() {
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, true)
+ setupGetSecurityView(SecurityMode.Password)
+ verify(view)
+ .initMode(
+ eq(KeyguardSecurityContainer.MODE_DEFAULT),
+ eq(globalSettings),
+ eq(falsingManager),
+ eq(userSwitcherController),
+ any(),
+ eq(falsingA11yDelegate)
+ )
+ }
+
+ @Test
+ fun addUserSwitcherCallback() {
+ val captor = ArgumentCaptor.forClass(UserSwitcherCallback::class.java)
+ setupGetSecurityView(SecurityMode.Password)
+ verify(view)
+ .initMode(anyInt(), any(), any(), any(), captor.capture(), eq(falsingA11yDelegate))
+ captor.value.showUnlockToContinueMessage()
+ viewControllerImmediately
+ verify(keyguardPasswordViewControllerMock)
+ .showMessage(
+ /* message= */ context.getString(R.string.keyguard_unlock_to_continue),
+ /* colorState= */ null,
+ /* animated= */ true
+ )
+ }
+
+ @Test
+ fun addUserSwitchCallback() {
+ underTest.onViewAttached()
+ verify(userSwitcherController).addUserSwitchCallback(any())
+ underTest.onViewDetached()
+ verify(userSwitcherController).removeUserSwitchCallback(any())
+ }
+
+ @Test
+ fun onBouncerVisibilityChanged_resetsScale() {
+ underTest.onBouncerVisibilityChanged(false)
+ verify(view).resetScale()
+ }
+
+ @Test
+ fun showNextSecurityScreenOrFinish_setsSecurityScreenToPinAfterSimPinUnlock() {
+ // GIVEN the current security method is SimPin
+ whenever(keyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false)
+ whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID))
+ .thenReturn(false)
+ underTest.showSecurityScreen(SecurityMode.SimPin)
+
+ // WHEN a request is made from the SimPin screens to show the next security method
+ whenever(keyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.PIN)
+ underTest.showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ TARGET_USER_ID,
+ /* bypassSecondaryLockScreen= */ true,
+ SecurityMode.SimPin
+ )
+
+ // THEN the next security method of PIN is set, and the keyguard is not marked as done
+ verify(viewMediatorCallback, never()).keyguardDonePending(anyBoolean(), anyInt())
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+ Truth.assertThat(underTest.currentSecurityMode).isEqualTo(SecurityMode.PIN)
+ }
+
+ @Test
+ fun showNextSecurityScreenOrFinish_DeviceNotSecure() {
+ // GIVEN the current security method is SimPin
+ whenever(keyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false)
+ whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID))
+ .thenReturn(false)
+ underTest.showSecurityScreen(SecurityMode.SimPin)
+
+ // WHEN a request is made from the SimPin screens to show the next security method
+ whenever(keyguardSecurityModel.getSecurityMode(TARGET_USER_ID))
+ .thenReturn(SecurityMode.None)
+ whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true)
+ underTest.showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ TARGET_USER_ID,
+ /* bypassSecondaryLockScreen= */ true,
+ SecurityMode.SimPin
+ )
+
+ // THEN the next security method of None will dismiss keyguard.
+ verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
+ }
+
+ @Test
+ fun showNextSecurityScreenOrFinish_ignoresCallWhenSecurityMethodHasChanged() {
+ // GIVEN current security mode has been set to PIN
+ underTest.showSecurityScreen(SecurityMode.PIN)
+
+ // WHEN a request comes from SimPin to dismiss the security screens
+ val keyguardDone =
+ underTest.showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ TARGET_USER_ID,
+ /* bypassSecondaryLockScreen= */ true,
+ SecurityMode.SimPin
+ )
+
+ // THEN no action has happened, which will not dismiss the security screens
+ Truth.assertThat(keyguardDone).isEqualTo(false)
+ verify(keyguardUpdateMonitor, never()).getUserHasTrust(anyInt())
+ }
+
+ @Test
+ fun showNextSecurityScreenOrFinish_SimPin_Swipe() {
+ // GIVEN the current security method is SimPin
+ whenever(keyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false)
+ whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID))
+ .thenReturn(false)
+ underTest.showSecurityScreen(SecurityMode.SimPin)
+
+ // WHEN a request is made from the SimPin screens to show the next security method
+ whenever(keyguardSecurityModel.getSecurityMode(TARGET_USER_ID))
+ .thenReturn(SecurityMode.None)
+ // WHEN security method is SWIPE
+ whenever(lockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false)
+ underTest.showNextSecurityScreenOrFinish(
+ /* authenticated= */ true,
+ TARGET_USER_ID,
+ /* bypassSecondaryLockScreen= */ true,
+ SecurityMode.SimPin
+ )
+
+ // THEN the next security method of None will dismiss keyguard.
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+ }
+
+ @Test
+ fun onSwipeUp_whenFaceDetectionIsNotRunning_initiatesFaceAuth() {
+ val registeredSwipeListener = registeredSwipeListener
+ whenever(keyguardUpdateMonitor.isFaceDetectionRunning).thenReturn(false)
+ setupGetSecurityView(SecurityMode.Password)
+ registeredSwipeListener.onSwipeUp()
+ verify(keyguardUpdateMonitor).requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
+ }
+
+ @Test
+ fun onSwipeUp_whenFaceDetectionIsRunning_doesNotInitiateFaceAuth() {
+ val registeredSwipeListener = registeredSwipeListener
+ whenever(keyguardUpdateMonitor.isFaceDetectionRunning).thenReturn(true)
+ registeredSwipeListener.onSwipeUp()
+ verify(keyguardUpdateMonitor, never())
+ .requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
+ }
+
+ @Test
+ fun onSwipeUp_whenFaceDetectionIsTriggered_hidesBouncerMessage() {
+ val registeredSwipeListener = registeredSwipeListener
+ whenever(
+ keyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
+ )
+ .thenReturn(true)
+ setupGetSecurityView(SecurityMode.Password)
+ clearInvocations(viewFlipperController)
+ registeredSwipeListener.onSwipeUp()
+ viewControllerImmediately
+ verify(keyguardPasswordViewControllerMock)
+ .showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true)
+ }
+
+ @Test
+ fun onSwipeUp_whenFaceDetectionIsNotTriggered_retainsBouncerMessage() {
+ val registeredSwipeListener = registeredSwipeListener
+ whenever(
+ keyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER)
+ )
+ .thenReturn(false)
+ setupGetSecurityView(SecurityMode.Password)
+ registeredSwipeListener.onSwipeUp()
+ verify(keyguardPasswordViewControllerMock, never())
+ .showMessage(/* message= */ null, /* colorState= */ null, /* animated= */ true)
+ }
+
+ @Test
+ fun onDensityOrFontScaleChanged() {
+ val configurationListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+ underTest.onViewAttached()
+ verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
+ clearInvocations(viewFlipperController)
+ configurationListenerArgumentCaptor.value.onDensityOrFontScaleChanged()
+ verify(viewFlipperController).clearViews()
+ verify(viewFlipperController)
+ .asynchronouslyInflateView(
+ eq(SecurityMode.PIN),
+ any(),
+ onViewInflatedCallbackArgumentCaptor.capture()
+ )
+ onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
+ verify(view).onDensityOrFontScaleChanged()
+ }
+
+ @Test
+ fun onThemeChanged() {
+ val configurationListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+ underTest.onViewAttached()
+ verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
+ clearInvocations(viewFlipperController)
+ configurationListenerArgumentCaptor.value.onThemeChanged()
+ verify(viewFlipperController).clearViews()
+ verify(viewFlipperController)
+ .asynchronouslyInflateView(
+ eq(SecurityMode.PIN),
+ any(),
+ onViewInflatedCallbackArgumentCaptor.capture()
+ )
+ onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
+ verify(view).reset()
+ verify(viewFlipperController).reset()
+ verify(view).reloadColors()
+ }
+
+ @Test
+ fun onUiModeChanged() {
+ val configurationListenerArgumentCaptor =
+ ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+ underTest.onViewAttached()
+ verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
+ clearInvocations(viewFlipperController)
+ configurationListenerArgumentCaptor.value.onUiModeChanged()
+ verify(viewFlipperController).clearViews()
+ verify(viewFlipperController)
+ .asynchronouslyInflateView(
+ eq(SecurityMode.PIN),
+ any(),
+ onViewInflatedCallbackArgumentCaptor.capture()
+ )
+ onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
+ verify(view).reloadColors()
+ }
+
+ @Test
+ fun hasDismissActions() {
+ Assert.assertFalse("Action not set yet", underTest.hasDismissActions())
+ underTest.setOnDismissAction(mock(), null /* cancelAction */)
+ Assert.assertTrue("Action should exist", underTest.hasDismissActions())
+ }
+
+ @Test
+ fun willRunDismissFromKeyguardIsTrue() {
+ val action: OnDismissAction = mock()
+ whenever(action.willRunAnimationOnKeyguard()).thenReturn(true)
+ underTest.setOnDismissAction(action, null /* cancelAction */)
+ underTest.finish(false /* strongAuth */, 0 /* currentUser */)
+ Truth.assertThat(underTest.willRunDismissFromKeyguard()).isTrue()
+ }
+
+ @Test
+ fun willRunDismissFromKeyguardIsFalse() {
+ val action: OnDismissAction = mock()
+ whenever(action.willRunAnimationOnKeyguard()).thenReturn(false)
+ underTest.setOnDismissAction(action, null /* cancelAction */)
+ underTest.finish(false /* strongAuth */, 0 /* currentUser */)
+ Truth.assertThat(underTest.willRunDismissFromKeyguard()).isFalse()
+ }
+
+ @Test
+ fun willRunDismissFromKeyguardIsFalseWhenNoDismissActionSet() {
+ underTest.setOnDismissAction(null /* action */, null /* cancelAction */)
+ underTest.finish(false /* strongAuth */, 0 /* currentUser */)
+ Truth.assertThat(underTest.willRunDismissFromKeyguard()).isFalse()
+ }
+
+ @Test
+ fun onStartingToHide() {
+ underTest.onStartingToHide()
+ verify(viewFlipperController)
+ .getSecurityView(any(), any(), onViewInflatedCallbackArgumentCaptor.capture())
+ onViewInflatedCallbackArgumentCaptor.value.onViewInflated(inputViewController)
+ verify(inputViewController).onStartingToHide()
+ }
+
+ @Test
+ fun gravityReappliedOnConfigurationChange() {
+ // Set initial gravity
+ testableResources.addOverride(R.integer.keyguard_host_view_gravity, Gravity.CENTER)
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, false)
+
+ // Kick off the initial pass...
+ underTest.onInit()
+ verify(view).layoutParams = any()
+ clearInvocations(view)
+
+ // Now simulate a config change
+ testableResources.addOverride(
+ R.integer.keyguard_host_view_gravity,
+ Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM
+ )
+ underTest.updateResources()
+ verify(view).layoutParams = any()
+ }
+
+ @Test
+ fun gravityUsesOneHandGravityWhenApplicable() {
+ testableResources.addOverride(R.integer.keyguard_host_view_gravity, Gravity.CENTER)
+ testableResources.addOverride(
+ R.integer.keyguard_host_view_one_handed_gravity,
+ Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM
+ )
+
+ // Start disabled.
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, false)
+ underTest.onInit()
+ verify(view).layoutParams =
+ argThat(
+ ArgumentMatcher { argument: FrameLayout.LayoutParams ->
+ argument.gravity == Gravity.CENTER
+ }
+ as ArgumentMatcher<FrameLayout.LayoutParams>
+ )
+ clearInvocations(view)
+
+ // And enable
+ testableResources.addOverride(R.bool.can_use_one_handed_bouncer, true)
+ underTest.updateResources()
+ verify(view).layoutParams =
+ argThat(
+ ArgumentMatcher { argument: FrameLayout.LayoutParams ->
+ argument.gravity == Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM
+ }
+ as ArgumentMatcher<FrameLayout.LayoutParams>
+ )
+ }
+
+ @Test
+ fun updateKeyguardPositionDelegatesToSecurityContainer() {
+ underTest.updateKeyguardPosition(1.0f)
+ verify(view).updatePositionByTouchX(1.0f)
+ }
+
+ @Test
+ fun reinflateViewFlipper() {
+ val onViewInflatedCallback = KeyguardSecurityViewFlipperController.OnViewInflatedCallback {}
+ underTest.reinflateViewFlipper(onViewInflatedCallback)
+ verify(viewFlipperController).clearViews()
+ verify(viewFlipperController)
+ .asynchronouslyInflateView(any(), any(), eq(onViewInflatedCallback))
+ }
+
+ @Test
+ fun sideFpsControllerShow() {
+ underTest.updateSideFpsVisibility(/* isVisible= */ true)
+ verify(sideFpsController)
+ .show(
+ SideFpsUiRequestSource.PRIMARY_BOUNCER,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ )
+ }
+
+ @Test
+ fun sideFpsControllerHide() {
+ underTest.updateSideFpsVisibility(/* isVisible= */ false)
+ verify(sideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER)
+ }
+
+ @Test
+ fun setExpansion_setsAlpha() {
+ underTest.setExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
+ verify(view).alpha = 1f
+ verify(view).translationY = 0f
+ }
+
+ @Test
+ fun dismissesKeyguard_whenSceneChangesFromBouncerToGone() =
+ sceneTestUtils.testScope.runTest {
+ featureFlags.set(Flags.SCENE_CONTAINER, true)
+
+ // Upon init, we have never dismisses the keyguard.
+ underTest.onInit()
+ runCurrent()
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+
+ // Once the view is attached, we start listening but simply going to the bouncer scene
+ // is
+ // not enough to trigger a dismissal of the keyguard.
+ underTest.onViewAttached()
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer, null)
+ )
+ runCurrent()
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+
+ // While listening, going from the bouncer scene to the gone scene, does dismiss the
+ // keyguard.
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Gone, null)
+ )
+ runCurrent()
+ verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
+
+ // While listening, moving back to the bouncer scene does not dismiss the keyguard
+ // again.
+ clearInvocations(viewMediatorCallback)
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer, null)
+ )
+ runCurrent()
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+
+ // Detaching the view stops listening, so moving from the bouncer scene to the gone
+ // scene
+ // does not dismiss the keyguard while we're not listening.
+ underTest.onViewDetached()
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Gone, null)
+ )
+ runCurrent()
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+
+ // While not listening, moving back to the bouncer does not dismiss the keyguard.
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer, null)
+ )
+ runCurrent()
+ verify(viewMediatorCallback, never()).keyguardDone(anyBoolean(), anyInt())
+
+ // Reattaching the view starts listening again so moving from the bouncer scene to the
+ // gone
+ // scene now does dismiss the keyguard again.
+ underTest.onViewAttached()
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Gone, null)
+ )
+ runCurrent()
+ verify(viewMediatorCallback).keyguardDone(anyBoolean(), anyInt())
+ }
+
+ private val registeredSwipeListener: KeyguardSecurityContainer.SwipeListener
+ get() {
+ underTest.onViewAttached()
+ verify(view).setSwipeListener(swipeListenerArgumentCaptor.capture())
+ return swipeListenerArgumentCaptor.value
+ }
+
+ private fun setupGetSecurityView(securityMode: SecurityMode) {
+ underTest.showSecurityScreen(securityMode)
+ viewControllerImmediately
+ }
+
+ private val viewControllerImmediately: Unit
+ get() {
+ verify(viewFlipperController, atLeastOnce())
+ .getSecurityView(any(), any(), onViewInflatedCallbackArgumentCaptor.capture())
+ @Suppress("UNCHECKED_CAST")
+ onViewInflatedCallbackArgumentCaptor.value.onViewInflated(
+ keyguardPasswordViewControllerMock as KeyguardInputViewController<KeyguardInputView>
+ )
+ }
+
+ companion object {
+ private const val TARGET_USER_ID = 100
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
index 75106e7..956e0b81 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.systemui.flags.Flags.DOZING_MIGRATION_1;
import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
import static com.android.systemui.flags.Flags.MIGRATE_LOCK_ICON;
import static org.mockito.Mockito.any;
@@ -147,6 +148,7 @@
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(FACE_AUTH_REFACTOR, false);
mFeatureFlags.set(MIGRATE_LOCK_ICON, false);
+ mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
mUnderTest = new LockIconViewController(
mLockIconView,
mStatusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
index d2c54b4..c372f45 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
@@ -17,9 +17,11 @@
package com.android.keyguard
import android.testing.AndroidTestingRunner
+import android.view.View
import androidx.test.filters.SmallTest
import com.android.keyguard.LockIconView.ICON_LOCK
import com.android.systemui.doze.util.getBurnInOffset
+import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
@@ -117,6 +119,33 @@
verify(mLockIconView).setTranslationX(0f)
}
+ @Test
+ fun testHideLockIconView_onLockscreenHostedDreamStateChanged() =
+ runBlocking(IMMEDIATE) {
+ // GIVEN starting state for the lock icon (keyguard) and wallpaper dream enabled
+ mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
+ setupShowLockIcon()
+ init(/* useMigrationFlag= */ true)
+ reset(mLockIconView)
+
+ // WHEN dream starts
+ mUnderTest.mIsActiveDreamLockscreenHostedCallback.accept(
+ true /* isActiveDreamLockscreenHosted */
+ )
+
+ // THEN the lock icon is hidden
+ verify(mLockIconView).visibility = View.INVISIBLE
+ reset(mLockIconView)
+
+ // WHEN the device is no longer dreaming
+ mUnderTest.mIsActiveDreamLockscreenHostedCallback.accept(
+ false /* isActiveDreamLockscreenHosted */
+ )
+
+ // THEN lock icon is visible
+ verify(mLockIconView).visibility = View.VISIBLE
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
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 caf230d..67d6aa8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java
@@ -198,6 +198,7 @@
assertTrue(mWindowMagnification.mUsersScales.contains(testUserId));
assertEquals(mWindowMagnification.mUsersScales.get(testUserId).get(TEST_DISPLAY),
(Float) testScale);
+ verify(mMagnificationSettingsController).setMagnificationScale(eq(testScale));
}
private class FakeControllerSupplier extends
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
index 62a176c9..9eead6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationSettingsControllerTest.java
@@ -86,6 +86,14 @@
}
@Test
+ public void testSetMagnificationScale() {
+ final float scale = 3.0f;
+ mMagnificationSettingsController.setMagnificationScale(scale);
+
+ verify(mWindowMagnificationSettings).setMagnificationScale(eq(scale));
+ }
+
+ @Test
public void testOnConfigurationChanged_notifySettingsPanel() {
mMagnificationSettingsController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
@@ -145,10 +153,11 @@
@Test
public void testPanelOnMagnifierScale_delegateToCallback() {
final float scale = 3.0f;
+ final boolean updatePersistence = true;
mMagnificationSettingsController.mWindowMagnificationSettingsCallback
- .onMagnifierScale(scale);
+ .onMagnifierScale(scale, updatePersistence);
verify(mMagnificationSettingControllerCallback).onMagnifierScale(
- eq(mContext.getDisplayId()), eq(scale));
+ eq(mContext.getDisplayId()), eq(scale), eq(updatePersistence));
}
}
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 31c09b8..56f8160 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -645,10 +645,12 @@
assertTrue(
mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_out, null));
// Minimum scale is 1.0.
- verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(1.0f));
+ verify(mWindowMagnifierCallback).onPerformScaleAction(
+ eq(displayId), /* scale= */ eq(1.0f), /* updatePersistence= */ eq(true));
assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_in, null));
- verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(2.5f));
+ verify(mWindowMagnifierCallback).onPerformScaleAction(
+ eq(displayId), /* scale= */ eq(2.5f), /* updatePersistence= */ eq(true));
// TODO: Verify the final state when the mirror surface is visible.
assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
index 275723b..eddb8d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.accessibility;
-import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
@@ -28,10 +27,12 @@
import static junit.framework.Assert.assertNotNull;
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.never;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -55,10 +56,11 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import com.android.internal.accessibility.common.MagnificationConstants;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView;
+import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView.OnSeekBarWithIconButtonsChangeListener;
import com.android.systemui.util.settings.SecureSettings;
import org.junit.After;
@@ -79,6 +81,7 @@
private static final int MAGNIFICATION_SIZE_LARGE = 3;
private ViewGroup mSettingView;
+ private SeekBarWithIconButtonsView mZoomSeekbar;
@Mock
private AccessibilityManager mAccessibilityManager;
@Mock
@@ -111,6 +114,7 @@
mSecureSettings);
mSettingView = mWindowMagnificationSettings.getSettingView();
+ mZoomSeekbar = mSettingView.findViewById(R.id.magnifier_zoom_slider);
mSecureSettingsScaleCaptor = ArgumentCaptor.forClass(Float.class);
mSecureSettingsNameCaptor = ArgumentCaptor.forClass(String.class);
mSecureSettingsUserHandleCaptor = ArgumentCaptor.forClass(Integer.class);
@@ -337,20 +341,6 @@
}
@Test
- public void showSettingsPanel_observerForMagnificationScaleRegistered() {
- setupMagnificationCapabilityAndMode(
- /* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_ALL,
- /* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
-
- mWindowMagnificationSettings.showSettingPanel();
-
- verify(mSecureSettings).registerContentObserverForUser(
- eq(ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE),
- any(ContentObserver.class),
- eq(UserHandle.USER_CURRENT));
- }
-
- @Test
public void hideSettingsPanel_observerUnregistered() {
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_ALL,
@@ -359,19 +349,25 @@
mWindowMagnificationSettings.showSettingPanel();
mWindowMagnificationSettings.hideSettingPanel();
- verify(mSecureSettings, times(2)).unregisterContentObserver(any(ContentObserver.class));
+ verify(mSecureSettings).unregisterContentObserver(any(ContentObserver.class));
}
@Test
public void seekbarProgress_justInflated_maxValueAndProgressSetCorrectly() {
- setupScaleInSecureSettings(0f);
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getProgress()).isEqualTo(0);
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getMax()).isEqualTo(70);
+ mWindowMagnificationSettings.setMagnificationScale(2f);
+ mWindowMagnificationSettings.inflateView();
+
+ // inflateView() would create new settingsView in WindowMagnificationSettings so we
+ // need to retrieve the new mZoomSeekbar
+ mSettingView = mWindowMagnificationSettings.getSettingView();
+ mZoomSeekbar = mSettingView.findViewById(R.id.magnifier_zoom_slider);
+ assertThat(mZoomSeekbar.getProgress()).isEqualTo(10);
+ assertThat(mZoomSeekbar.getMax()).isEqualTo(70);
}
@Test
public void seekbarProgress_minMagnification_seekbarProgressIsCorrect() {
- setupScaleInSecureSettings(0f);
+ mWindowMagnificationSettings.setMagnificationScale(1f);
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
/* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
@@ -379,24 +375,24 @@
mWindowMagnificationSettings.showSettingPanel();
// Seekbar index from 0 to 70. 1.0f scale (A11Y_SCALE_MIN_VALUE) would correspond to 0.
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getProgress()).isEqualTo(0);
+ assertThat(mZoomSeekbar.getProgress()).isEqualTo(0);
}
@Test
public void seekbarProgress_belowMinMagnification_seekbarProgressIsZero() {
- setupScaleInSecureSettings(0f);
+ mWindowMagnificationSettings.setMagnificationScale(0f);
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
/* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
mWindowMagnificationSettings.showSettingPanel();
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getProgress()).isEqualTo(0);
+ assertThat(mZoomSeekbar.getProgress()).isEqualTo(0);
}
@Test
public void seekbarProgress_magnificationBefore_seekbarProgressIsHalf() {
- setupScaleInSecureSettings(4f);
+ mWindowMagnificationSettings.setMagnificationScale(4f);
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
/* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
@@ -405,12 +401,12 @@
// float scale : from 1.0f to 8.0f, seekbar index from 0 to 70.
// 4.0f would correspond to 30.
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getProgress()).isEqualTo(30);
+ assertThat(mZoomSeekbar.getProgress()).isEqualTo(30);
}
@Test
public void seekbarProgress_maxMagnificationBefore_seekbarProgressIsMax() {
- setupScaleInSecureSettings(8f);
+ mWindowMagnificationSettings.setMagnificationScale(8f);
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
/* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
@@ -419,12 +415,12 @@
// 8.0f is max magnification {@link MagnificationScaleProvider#MAX_SCALE}.
// Max zoom seek bar is 70.
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getProgress()).isEqualTo(70);
+ assertThat(mZoomSeekbar.getProgress()).isEqualTo(70);
}
@Test
public void seekbarProgress_aboveMaxMagnificationBefore_seekbarProgressIsMax() {
- setupScaleInSecureSettings(9f);
+ mWindowMagnificationSettings.setMagnificationScale(9f);
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
/* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
@@ -432,88 +428,81 @@
mWindowMagnificationSettings.showSettingPanel();
// Max zoom seek bar is 70.
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getProgress()).isEqualTo(70);
+ assertThat(mZoomSeekbar.getProgress()).isEqualTo(70);
}
@Test
- public void seekbarProgress_progressChangedRoughlyHalf_scaleAndCallbackUpdated() {
- setupMagnificationCapabilityAndMode(
- /* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
- /* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
- mWindowMagnificationSettings.showSettingPanel();
+ public void onSeekBarProgressChanged_fromUserFalse_callbackNotTriggered() {
+ OnSeekBarWithIconButtonsChangeListener onChangeListener =
+ mZoomSeekbar.getOnSeekBarWithIconButtonsChangeListener();
+ onChangeListener.onProgressChanged(
+ mZoomSeekbar.getSeekbar(), /* progress= */ 30, /* fromUser= */ false);
- mWindowMagnificationSettings.mZoomSeekbar.setProgress(30);
+ verify(mWindowMagnificationSettingsCallback, never())
+ .onMagnifierScale(/* scale= */ anyFloat(), /* updatePersistence= */ eq(false));
+ }
- verifyScaleUpdatedInSecureSettings(4f);
+ @Test
+ public void onSeekBarProgressChangedToRoughlyHalf_fromUserTrue_callbackUpdated() {
+ OnSeekBarWithIconButtonsChangeListener onChangeListener =
+ mZoomSeekbar.getOnSeekBarWithIconButtonsChangeListener();
+ onChangeListener.onProgressChanged(
+ mZoomSeekbar.getSeekbar(), /* progress= */ 30, /* fromUser= */ true);
+
verifyCallbackOnMagnifierScale(4f);
}
@Test
- public void seekbarProgress_minProgress_callbackUpdated() {
- setupMagnificationCapabilityAndMode(
- /* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
- /* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
- mWindowMagnificationSettings.showSettingPanel();
- // Set progress to non-zero first so onProgressChanged can be triggered upon setting to 0.
- mWindowMagnificationSettings.mZoomSeekbar.setProgress(30);
+ public void onSeekBarProgressChangedToMin_fromUserTrue_callbackUpdated() {
+ OnSeekBarWithIconButtonsChangeListener onChangeListener =
+ mZoomSeekbar.getOnSeekBarWithIconButtonsChangeListener();
+ onChangeListener.onProgressChanged(
+ mZoomSeekbar.getSeekbar(), /* progress= */ 0, /* fromUser= */ true);
- mWindowMagnificationSettings.mZoomSeekbar.setProgress(0);
-
- // For now, secure settings will not be updated for values < 1.3f. Follow up on this later.
- verify(mWindowMagnificationSettingsCallback, times(2))
- .onMagnifierScale(mCallbackMagnifierScaleCaptor.capture());
- var capturedArgs = mCallbackMagnifierScaleCaptor.getAllValues();
- assertThat(capturedArgs).hasSize(2);
- assertThat(capturedArgs.get(1)).isWithin(0.01f).of(1f);
+ verifyCallbackOnMagnifierScale(1f);
}
@Test
- public void seekbarProgress_maxProgress_scaleAndCallbackUpdated() {
- setupMagnificationCapabilityAndMode(
- /* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW,
- /* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
- mWindowMagnificationSettings.showSettingPanel();
+ public void onSeekBarProgressChangedToMax_fromUserTrue_callbackUpdated() {
+ OnSeekBarWithIconButtonsChangeListener onChangeListener =
+ mZoomSeekbar.getOnSeekBarWithIconButtonsChangeListener();
+ onChangeListener.onProgressChanged(
+ mZoomSeekbar.getSeekbar(), /* progress= */ 70, /* fromUser= */ true);
- mWindowMagnificationSettings.mZoomSeekbar.setProgress(70);
-
- verifyScaleUpdatedInSecureSettings(8f);
verifyCallbackOnMagnifierScale(8f);
}
@Test
+ public void onSeekbarUserInteractionFinalized_persistedScaleUpdated() {
+ OnSeekBarWithIconButtonsChangeListener onChangeListener =
+ mZoomSeekbar.getOnSeekBarWithIconButtonsChangeListener();
+
+ mZoomSeekbar.setProgress(30);
+ onChangeListener.onUserInteractionFinalized(
+ mZoomSeekbar.getSeekbar(),
+ OnSeekBarWithIconButtonsChangeListener.ControlUnitType.SLIDER);
+
+ // should trigger callback to update magnifier scale and persist the scale
+ verify(mWindowMagnificationSettingsCallback)
+ .onMagnifierScale(/* scale= */ eq(4f), /* updatePersistence= */ eq(true));
+ }
+
+ @Test
public void seekbarProgress_scaleUpdatedAfterSettingPanelOpened_progressAlsoUpdated() {
setupMagnificationCapabilityAndMode(
/* capability= */ ACCESSIBILITY_MAGNIFICATION_MODE_ALL,
/* mode= */ ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
- var contentObserverCaptor = ArgumentCaptor.forClass(ContentObserver.class);
mWindowMagnificationSettings.showSettingPanel();
- verify(mSecureSettings).registerContentObserverForUser(
- eq(ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE),
- contentObserverCaptor.capture(),
- eq(UserHandle.USER_CURRENT));
// Simulate outside changes.
- setupScaleInSecureSettings(4f);
- // Simulate callback due to outside change.
- contentObserverCaptor.getValue().onChange(/* selfChange= */ false);
+ mWindowMagnificationSettings.setMagnificationScale(4f);
- assertThat(mWindowMagnificationSettings.mZoomSeekbar.getProgress()).isEqualTo(30);
- }
-
- private void verifyScaleUpdatedInSecureSettings(float scale) {
- verify(mSecureSettings).putFloatForUser(
- mSecureSettingsNameCaptor.capture(),
- mSecureSettingsScaleCaptor.capture(),
- mSecureSettingsUserHandleCaptor.capture());
- assertThat(mSecureSettingsScaleCaptor.getValue()).isWithin(0.01f).of(scale);
- assertThat(mSecureSettingsNameCaptor.getValue())
- .isEqualTo(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE);
- assertThat(mSecureSettingsUserHandleCaptor.getValue()).isEqualTo(UserHandle.USER_CURRENT);
+ assertThat(mZoomSeekbar.getProgress()).isEqualTo(30);
}
private void verifyCallbackOnMagnifierScale(float scale) {
verify(mWindowMagnificationSettingsCallback)
- .onMagnifierScale(mCallbackMagnifierScaleCaptor.capture());
+ .onMagnifierScale(mCallbackMagnifierScaleCaptor.capture(), anyBoolean());
assertThat(mCallbackMagnifierScaleCaptor.getValue()).isWithin(0.01f).of(scale);
}
@@ -533,11 +522,4 @@
anyInt(),
eq(UserHandle.USER_CURRENT))).thenReturn(mode);
}
-
- private void setupScaleInSecureSettings(float scale) {
- when(mSecureSettings.getFloatForUser(
- ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- MagnificationConstants.SCALE_MIN_VALUE,
- UserHandle.USER_CURRENT)).thenReturn(scale);
- }
}
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 104ca69..d7b6602 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -165,13 +165,15 @@
@Test
public void onPerformScaleAction_enabled_notifyCallback() throws RemoteException {
final float newScale = 4.0f;
+ final boolean updatePersistence = true;
mCommandQueue.requestWindowMagnificationConnection(true);
waitForIdleSync();
mWindowMagnification.mWindowMagnifierCallback
- .onPerformScaleAction(TEST_DISPLAY, newScale);
+ .onPerformScaleAction(TEST_DISPLAY, newScale, updatePersistence);
- verify(mConnectionCallback).onPerformScaleAction(TEST_DISPLAY, newScale);
+ verify(mConnectionCallback).onPerformScaleAction(
+ eq(TEST_DISPLAY), eq(newScale), eq(updatePersistence));
}
@Test
@@ -255,10 +257,12 @@
mCommandQueue.requestWindowMagnificationConnection(true);
waitForIdleSync();
final float scale = 3.0f;
+ final boolean updatePersistence = false;
mWindowMagnification.mMagnificationSettingsControllerCallback.onMagnifierScale(
- TEST_DISPLAY, scale);
+ TEST_DISPLAY, scale, updatePersistence);
- verify(mConnectionCallback).onPerformScaleAction(eq(TEST_DISPLAY), eq(scale));
+ verify(mConnectionCallback).onPerformScaleAction(
+ eq(TEST_DISPLAY), eq(scale), eq(updatePersistence));
verify(mA11yLogger).logThrottled(
eq(MagnificationSettingsEvent.MAGNIFICATION_SETTINGS_ZOOM_SLIDER_CHANGED));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
index ea3289c..c0c6908 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorTest.kt
@@ -20,11 +20,16 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.AuthenticationRepository
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -47,25 +52,57 @@
@Test
fun getAuthenticationMethod() =
testScope.runTest {
- assertThat(underTest.getAuthenticationMethod())
- .isEqualTo(AuthenticationMethodModel.Pin(1234))
+ assertThat(underTest.getAuthenticationMethod()).isEqualTo(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
+
assertThat(underTest.getAuthenticationMethod())
- .isEqualTo(AuthenticationMethodModel.Password("password"))
+ .isEqualTo(AuthenticationMethodModel.Password)
}
@Test
- fun isUnlocked_whenAuthMethodIsNone_isTrue() =
+ fun getAuthenticationMethod_noneTreatedAsSwipe_whenLockscreenEnabled() =
testScope.runTest {
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setLockscreenEnabled(true)
+
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.Swipe)
+ }
+
+ @Test
+ fun getAuthenticationMethod_none_whenLockscreenDisabled() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setLockscreenEnabled(false)
+
+ assertThat(underTest.getAuthenticationMethod())
+ .isEqualTo(AuthenticationMethodModel.None)
+ }
+
+ @Test
+ fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setLockscreenEnabled(false)
+
val isUnlocked by collectLastValue(underTest.isUnlocked)
assertThat(isUnlocked).isTrue()
}
@Test
+ fun isUnlocked_whenAuthMethodIsNoneAndLockscreenEnabled_isFalse() =
+ testScope.runTest {
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
+ utils.authenticationRepository.setLockscreenEnabled(true)
+
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ assertThat(isUnlocked).isFalse()
+ }
+
+ @Test
fun toggleBypassEnabled() =
testScope.runTest {
val isBypassEnabled by collectLastValue(underTest.isBypassEnabled)
@@ -84,7 +121,7 @@
utils.authenticationRepository.setUnlocked(false)
runCurrent()
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
assertThat(underTest.isAuthenticationRequired()).isTrue()
@@ -106,7 +143,7 @@
utils.authenticationRepository.setUnlocked(true)
runCurrent()
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
assertThat(underTest.isAuthenticationRequired()).isFalse()
@@ -125,49 +162,33 @@
@Test
fun authenticate_withCorrectPin_returnsTrue() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
-
+ val isThrottled by collectLastValue(underTest.isThrottled)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
- assertThat(failedAttemptCount).isEqualTo(0)
+ assertThat(isThrottled).isFalse()
}
@Test
fun authenticate_withIncorrectPin_returnsFalse() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
-
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
}
- @Test
- fun authenticate_withEmptyPin_returnsFalse() =
+ @Test(expected = IllegalArgumentException::class)
+ fun authenticate_withEmptyPin_throwsException() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
-
- assertThat(underTest.authenticate(listOf())).isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ underTest.authenticate(listOf())
}
@Test
fun authenticate_withCorrectMaxLengthPin_returnsTrue() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(9999999999999999)
- )
-
- assertThat(underTest.authenticate(List(16) { 9 })).isTrue()
- assertThat(failedAttemptCount).isEqualTo(0)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ val pin = List(16) { 9 }
+ utils.authenticationRepository.overrideCredential(pin)
+ assertThat(underTest.authenticate(pin)).isTrue()
}
@Test
@@ -179,105 +200,47 @@
// If the policy changes, there is work to do in SysUI.
assertThat(DevicePolicyManager.MAX_PASSWORD_LENGTH).isLessThan(17)
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(99999999999999999)
- )
-
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(underTest.authenticate(List(17) { 9 })).isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
}
@Test
fun authenticate_withCorrectPassword_returnsTrue() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isThrottled by collectLastValue(underTest.isThrottled)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
assertThat(underTest.authenticate("password".toList())).isTrue()
- assertThat(failedAttemptCount).isEqualTo(0)
+ assertThat(isThrottled).isFalse()
}
@Test
fun authenticate_withIncorrectPassword_returnsFalse() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
assertThat(underTest.authenticate("alohomora".toList())).isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
}
@Test
fun authenticate_withCorrectPattern_returnsTrue() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(
- listOf(
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 0,
- ),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 1,
- ),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 2,
- ),
- )
- )
+ AuthenticationMethodModel.Pattern
)
- assertThat(
- underTest.authenticate(
- listOf(
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 0,
- ),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 1,
- ),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 2,
- ),
- )
- )
- )
- .isTrue()
- assertThat(failedAttemptCount).isEqualTo(0)
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN)).isTrue()
}
@Test
fun authenticate_withIncorrectPattern_returnsFalse() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(
- listOf(
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 0,
- ),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 1,
- ),
- AuthenticationMethodModel.Pattern.PatternCoordinate(
- x = 0,
- y = 2,
- ),
- )
- )
+ AuthenticationMethodModel.Pattern
)
assertThat(
@@ -299,91 +262,159 @@
)
)
.isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
- }
-
- @Test
- fun tryAutoConfirm_withAutoConfirmPinAndEmptyInput_returnsNull() =
- testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
-
- assertThat(underTest.authenticate(listOf(), tryAutoConfirm = true)).isNull()
- assertThat(failedAttemptCount).isEqualTo(0)
}
@Test
fun tryAutoConfirm_withAutoConfirmPinAndShorterPin_returnsNullAndHasNoEffect() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
-
+ val isThrottled by collectLastValue(underTest.isThrottled)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(underTest.authenticate(listOf(1, 2, 3), tryAutoConfirm = true)).isNull()
- assertThat(failedAttemptCount).isEqualTo(0)
+ assertThat(isThrottled).isFalse()
}
@Test
fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
-
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
+ assertThat(isUnlocked).isFalse()
}
@Test
fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
-
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(underTest.authenticate(listOf(1, 2, 3, 4, 5), tryAutoConfirm = true))
.isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
+ assertThat(isUnlocked).isFalse()
}
@Test
fun tryAutoConfirm_withAutoConfirmCorrectPin_returnsTrueAndUnlocksDevice() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
-
- assertThat(underTest.authenticate(listOf(1, 2, 4, 4), tryAutoConfirm = true)).isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isTrue()
+ assertThat(isUnlocked).isTrue()
}
@Test
fun tryAutoConfirm_withoutAutoConfirmButCorrectPin_returnsNullAndHasNoEffects() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = false)
- )
-
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(false)
assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isNull()
- assertThat(failedAttemptCount).isEqualTo(0)
+ assertThat(isUnlocked).isFalse()
}
@Test
fun tryAutoConfirm_withoutCorrectPassword_returnsNullAndHasNoEffects() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
assertThat(underTest.authenticate("password".toList(), tryAutoConfirm = true)).isNull()
- assertThat(failedAttemptCount).isEqualTo(0)
+ assertThat(isUnlocked).isFalse()
+ }
+
+ @Test
+ fun throttling() =
+ testScope.runTest {
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ val throttling by collectLastValue(underTest.throttling)
+ val isThrottled by collectLastValue(underTest.isThrottled)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ underTest.authenticate(listOf(1, 2, 3, 4))
+ assertThat(isUnlocked).isTrue()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
+
+ utils.authenticationRepository.setUnlocked(false)
+ assertThat(isUnlocked).isFalse()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
+
+ // Make many wrong attempts, but just shy of what's needed to get throttled:
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING - 1) {
+ underTest.authenticate(listOf(5, 6, 7)) // Wrong PIN
+ assertThat(isUnlocked).isFalse()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
+ }
+
+ // Make one more wrong attempt, leading to throttling:
+ underTest.authenticate(listOf(5, 6, 7)) // Wrong PIN
+ assertThat(isUnlocked).isFalse()
+ assertThat(isThrottled).isTrue()
+ assertThat(throttling)
+ .isEqualTo(
+ AuthenticationThrottlingModel(
+ failedAttemptCount =
+ FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING,
+ remainingMs = FakeAuthenticationRepository.THROTTLE_DURATION_MS,
+ )
+ )
+
+ // Correct PIN, but throttled, so doesn't attempt it:
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isNull()
+ assertThat(isUnlocked).isFalse()
+ assertThat(isThrottled).isTrue()
+ assertThat(throttling)
+ .isEqualTo(
+ AuthenticationThrottlingModel(
+ failedAttemptCount =
+ FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING,
+ remainingMs = FakeAuthenticationRepository.THROTTLE_DURATION_MS,
+ )
+ )
+
+ // Move the clock forward to ALMOST skip the throttling, leaving one second to go:
+ val throttleTimeoutSec =
+ FakeAuthenticationRepository.THROTTLE_DURATION_MS.milliseconds.inWholeSeconds
+ .toInt()
+ repeat(throttleTimeoutSec - 1) { time ->
+ advanceTimeBy(1000)
+ assertThat(isThrottled).isTrue()
+ assertThat(throttling)
+ .isEqualTo(
+ AuthenticationThrottlingModel(
+ failedAttemptCount =
+ FakeAuthenticationRepository
+ .MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING,
+ remainingMs =
+ ((throttleTimeoutSec - (time + 1)).seconds.inWholeMilliseconds)
+ .toInt(),
+ )
+ )
+ }
+
+ // Move the clock forward one more second, to completely finish the throttling period:
+ advanceTimeBy(1000)
+ assertThat(isUnlocked).isFalse()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling)
+ .isEqualTo(
+ AuthenticationThrottlingModel(
+ failedAttemptCount =
+ FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING,
+ remainingMs = 0,
+ )
+ )
+
+ // Correct PIN and no longer throttled so unlocks successfully:
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
+ assertThat(isUnlocked).isTrue()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index d31a86a..e3e6130 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -51,6 +51,7 @@
import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -99,6 +100,8 @@
lateinit var windowToken: IBinder
@Mock
lateinit var interactionJankMonitor: InteractionJankMonitor
+ @Mock
+ lateinit var vibrator: VibratorHelper
// TODO(b/278622168): remove with flag
open val useNewBiometricPrompt = false
@@ -325,7 +328,7 @@
authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
- container.animateToCredentialUI()
+ container.animateToCredentialUI(false)
waitForIdleSync()
assertThat(container.hasCredentialView()).isTrue()
@@ -514,7 +517,7 @@
{ authBiometricFingerprintViewModel },
{ promptSelectorInteractor },
{ bpCredentialInteractor },
- PromptViewModel(promptSelectorInteractor),
+ PromptViewModel(promptSelectorInteractor, vibrator),
{ credentialViewModel },
Handler(TestableLooper.get(this).looper),
fakeExecutor
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 5cae23c..3d4171f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -191,6 +191,10 @@
private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
@Captor
private ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
+ @Captor
+ private ArgumentCaptor<Integer> mModalityCaptor;
+ @Captor
+ private ArgumentCaptor<String> mMessageCaptor;
@Mock
private Resources mResources;
@@ -202,9 +206,6 @@
private TestableAuthController mAuthController;
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
- @Mock
- private VibratorHelper mVibratorHelper;
-
@Before
public void setup() throws RemoteException {
// TODO(b/278622168): remove with flag
@@ -267,7 +268,6 @@
true /* supportsSelfIllumination */,
true /* resetLockoutRequireHardwareAuthToken */));
when(mFaceManager.getSensorPropertiesInternal()).thenReturn(faceProps);
- when(mVibratorHelper.hasVibrator()).thenReturn(true);
mAuthController = new TestableAuthController(mContextSpy);
@@ -482,17 +482,26 @@
BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
0 /* vendorCode */);
- ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
+ verify(mDialog1).onAuthenticationFailed(mModalityCaptor.capture(), mMessageCaptor.capture());
- assertEquals(modalityCaptor.getValue().intValue(), modality);
- assertEquals(messageCaptor.getValue(),
+ assertEquals(mModalityCaptor.getValue().intValue(), modality);
+ assertEquals(mMessageCaptor.getValue(),
mContext.getString(R.string.biometric_not_recognized));
}
@Test
- public void testOnAuthenticationFailedInvoked_whenFaceAuthRejected() throws RemoteException {
+ public void testOnAuthenticationFailedInvoked_coex_whenFaceAuthRejected_withPaused() {
+ testOnAuthenticationFailedInvoked_coex_whenFaceAuthRejected(
+ BiometricConstants.BIOMETRIC_PAUSED_REJECTED);
+ }
+
+ @Test
+ public void testOnAuthenticationFailedInvoked_coex_whenFaceAuthRejected_withTimeout() {
+ testOnAuthenticationFailedInvoked_coex_whenFaceAuthRejected(
+ BiometricConstants.BIOMETRIC_ERROR_TIMEOUT);
+ }
+
+ private void testOnAuthenticationFailedInvoked_coex_whenFaceAuthRejected(int error) {
final int modality = BiometricAuthenticator.TYPE_FACE;
final int userId = 0;
@@ -500,16 +509,12 @@
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- mAuthController.onBiometricError(modality,
- BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
- 0 /* vendorCode */);
+ mAuthController.onBiometricError(modality, error, 0 /* vendorCode */);
- ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
+ verify(mDialog1).onAuthenticationFailed(mModalityCaptor.capture(), mMessageCaptor.capture());
- assertEquals(modalityCaptor.getValue().intValue(), modality);
- assertEquals(messageCaptor.getValue(),
+ assertThat(mModalityCaptor.getValue().intValue()).isEqualTo(modality);
+ assertThat(mMessageCaptor.getValue()).isEqualTo(
mContext.getString(R.string.biometric_face_not_recognized));
}
@@ -526,12 +531,10 @@
BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
0 /* vendorCode */);
- ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
+ verify(mDialog1).onAuthenticationFailed(mModalityCaptor.capture(), mMessageCaptor.capture());
- assertEquals(modalityCaptor.getValue().intValue(), modality);
- assertEquals(messageCaptor.getValue(),
+ assertThat(mModalityCaptor.getValue().intValue()).isEqualTo(modality);
+ assertThat(mMessageCaptor.getValue()).isEqualTo(
mContext.getString(R.string.fingerprint_error_not_match));
}
@@ -543,13 +546,11 @@
final int vendorCode = 0;
mAuthController.onBiometricError(modality, error, vendorCode);
- ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
+ verify(mDialog1).onAuthenticationFailed(mModalityCaptor.capture(), mMessageCaptor.capture());
- assertEquals(modalityCaptor.getValue().intValue(), modality);
- assertEquals(messageCaptor.getValue(),
- FaceManager.getErrorString(mContext, error, vendorCode));
+ assertThat(mModalityCaptor.getValue().intValue()).isEqualTo(modality);
+ assertThat(mMessageCaptor.getValue()).isEqualTo(
+ mContext.getString(R.string.biometric_not_recognized));
}
@Test
@@ -559,12 +560,10 @@
final String helpMessage = "help";
mAuthController.onBiometricHelp(modality, helpMessage);
- ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onHelp(modalityCaptor.capture(), messageCaptor.capture());
+ verify(mDialog1).onHelp(mModalityCaptor.capture(), mMessageCaptor.capture());
- assertEquals(modalityCaptor.getValue().intValue(), modality);
- assertEquals(messageCaptor.getValue(), helpMessage);
+ assertThat(mModalityCaptor.getValue().intValue()).isEqualTo(modality);
+ assertThat(mMessageCaptor.getValue()).isEqualTo(helpMessage);
}
@Test
@@ -575,12 +574,10 @@
final int vendorCode = 0;
mAuthController.onBiometricError(modality, error, vendorCode);
- ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
- ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onError(modalityCaptor.capture(), messageCaptor.capture());
+ verify(mDialog1).onError(mModalityCaptor.capture(), mMessageCaptor.capture());
- assertEquals(modalityCaptor.getValue().intValue(), modality);
- assertEquals(messageCaptor.getValue(),
+ assertThat(mModalityCaptor.getValue().intValue()).isEqualTo(modality);
+ assertThat(mMessageCaptor.getValue()).isEqualTo(
FaceManager.getErrorString(mContext, error, vendorCode));
}
@@ -594,7 +591,7 @@
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
verify(mDialog1, never()).onError(anyInt(), anyString());
- verify(mDialog1).animateToCredentialUI();
+ verify(mDialog1).animateToCredentialUI(eq(true));
}
@Test
@@ -607,7 +604,7 @@
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
verify(mDialog1, never()).onError(anyInt(), anyString());
- verify(mDialog1).animateToCredentialUI();
+ verify(mDialog1).animateToCredentialUI(eq(true));
}
@Test
@@ -622,7 +619,7 @@
mAuthController.onBiometricError(modality, error, vendorCode);
verify(mDialog1).onError(
eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
- verify(mDialog1, never()).animateToCredentialUI();
+ verify(mDialog1, never()).animateToCredentialUI(eq(true));
}
@Test
@@ -637,7 +634,7 @@
mAuthController.onBiometricError(modality, error, vendorCode);
verify(mDialog1).onError(
eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
- verify(mDialog1, never()).animateToCredentialUI();
+ verify(mDialog1, never()).animateToCredentialUI(eq(true));
}
@Test
@@ -1100,7 +1097,7 @@
() -> mBiometricPromptCredentialInteractor, () -> mPromptSelectionInteractor,
() -> mCredentialViewModel, () -> mPromptViewModel,
mInteractionJankMonitor, mHandler,
- mBackgroundExecutor, mVibratorHelper, mUdfpsUtils);
+ mBackgroundExecutor, mUdfpsUtils);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
index 97d3e68..5eda2b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractorImplTest.kt
@@ -11,8 +11,8 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
-import com.android.systemui.biometrics.domain.model.BiometricUserInfo
import com.android.systemui.biometrics.promptInfo
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
index 720a35c9..dcefea2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractorTest.kt
@@ -7,8 +7,8 @@
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.domain.model.BiometricOperationInfo
import com.android.systemui.biometrics.domain.model.BiometricPromptRequest
-import com.android.systemui.biometrics.domain.model.BiometricUserInfo
import com.android.systemui.biometrics.promptInfo
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
index e352905..be0276a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt
@@ -4,6 +4,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
import com.android.systemui.biometrics.promptInfo
+import com.android.systemui.biometrics.shared.model.BiometricUserInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
index fff1b81..278a43e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptAuthStateTest.kt
@@ -18,7 +18,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.domain.model.BiometricModality
+import com.android.systemui.biometrics.shared.model.BiometricModality
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 5b3edab..91140a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -27,11 +27,14 @@
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
import com.android.systemui.biometrics.domain.model.BiometricModalities
-import com.android.systemui.biometrics.domain.model.BiometricModality
import com.android.systemui.biometrics.extractAuthenticatorTypes
import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
+import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.mockito.any
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.first
@@ -45,6 +48,9 @@
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
private const val USER_ID = 4
@@ -58,6 +64,7 @@
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
@Mock private lateinit var lockPatternUtils: LockPatternUtils
+ @Mock private lateinit var vibrator: VibratorHelper
private val testScope = TestScope()
private val promptRepository = FakePromptRepository()
@@ -70,11 +77,11 @@
selector = PromptSelectorInteractorImpl(promptRepository, lockPatternUtils)
selector.resetPrompt()
- viewModel = PromptViewModel(selector)
+ viewModel = PromptViewModel(selector, vibrator)
}
@Test
- fun `start idle and show authenticating`() =
+ fun start_idle_and_show_authenticating() =
runGenericTest(doNotStart = true) {
val expectedSize =
if (testCase.shouldStartAsImplicitFlow) PromptSize.SMALL else PromptSize.MEDIUM
@@ -107,7 +114,7 @@
}
@Test
- fun `shows authenticated - no errors`() = runGenericTest {
+ fun shows_authenticated_with_no_errors() = runGenericTest {
// this case can't happen until fingerprint is started
// trigger it now since no error has occurred in this test
val forceError = testCase.isCoex && testCase.authenticatedByFingerprint
@@ -124,6 +131,24 @@
)
}
+ @Test
+ fun play_haptic_on_confirm_when_confirmation_required_otherwise_on_authenticated() =
+ runGenericTest {
+ val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
+
+ viewModel.showAuthenticated(testCase.authenticatedModality, 1_000L)
+
+ verify(vibrator, if (expectConfirmation) never() else times(1))
+ .vibrateAuthSuccess(any())
+
+ if (expectConfirmation) {
+ viewModel.confirmAuthenticated()
+ }
+
+ verify(vibrator).vibrateAuthSuccess(any())
+ verify(vibrator, never()).vibrateAuthError(any())
+ }
+
private suspend fun TestScope.showAuthenticated(
authenticatedModality: BiometricModality,
expectConfirmation: Boolean,
@@ -172,7 +197,7 @@
}
@Test
- fun `shows temporary errors`() = runGenericTest {
+ fun shows_temporary_errors() = runGenericTest {
val checkAtEnd = suspend { assertButtonsVisible(negative = true) }
showTemporaryErrors(restart = false) { checkAtEnd() }
@@ -180,6 +205,32 @@
showTemporaryErrors(restart = true) { checkAtEnd() }
}
+ @Test
+ fun plays_haptic_on_errors() = runGenericTest {
+ viewModel.showTemporaryError(
+ "so sad",
+ messageAfterError = "",
+ authenticateAfterError = false,
+ hapticFeedback = true,
+ )
+
+ verify(vibrator).vibrateAuthError(any())
+ verify(vibrator, never()).vibrateAuthSuccess(any())
+ }
+
+ @Test
+ fun plays_haptic_on_errors_unless_skipped() = runGenericTest {
+ viewModel.showTemporaryError(
+ "still sad",
+ messageAfterError = "",
+ authenticateAfterError = false,
+ hapticFeedback = false,
+ )
+
+ verify(vibrator, never()).vibrateAuthError(any())
+ verify(vibrator, never()).vibrateAuthSuccess(any())
+ }
+
private suspend fun TestScope.showTemporaryErrors(
restart: Boolean,
helpAfterError: String = "",
@@ -233,7 +284,7 @@
}
@Test
- fun `no errors or temporary help after authenticated`() = runGenericTest {
+ fun no_errors_or_temporary_help_after_authenticated() = runGenericTest {
val authenticating by collectLastValue(viewModel.isAuthenticating)
val authenticated by collectLastValue(viewModel.isAuthenticated)
val message by collectLastValue(viewModel.message)
@@ -249,7 +300,13 @@
assertThat(canTryAgain).isFalse()
}
- val errorJob = launch { viewModel.showTemporaryError("error") }
+ val errorJob = launch {
+ viewModel.showTemporaryError(
+ "error",
+ messageAfterError = "",
+ authenticateAfterError = false,
+ )
+ }
verifyNoError()
errorJob.join()
verifyNoError()
@@ -268,16 +325,70 @@
assertThat(messageIsShowing).isTrue()
}
- // @Test
- fun `suppress errors`() = runGenericTest {
- val errorMessage = "woot"
- val message by collectLastValue(viewModel.message)
+ @Test
+ fun suppress_temporary_error() = runGenericTest {
+ val messages by collectValues(viewModel.message)
- val errorJob = launch { viewModel.showTemporaryError(errorMessage) }
+ for (error in listOf("never", "see", "me")) {
+ launch {
+ viewModel.showTemporaryError(
+ error,
+ messageAfterError = "or me",
+ authenticateAfterError = false,
+ suppressIf = { _ -> true },
+ )
+ }
+ }
+
+ testScheduler.advanceUntilIdle()
+ assertThat(messages).containsExactly(PromptMessage.Empty)
}
@Test
- fun `authenticated at most once`() = runGenericTest {
+ fun suppress_temporary_error_when_already_showing_when_requested() =
+ suppress_temporary_error_when_already_showing(suppress = true)
+
+ @Test
+ fun do_not_suppress_temporary_error_when_already_showing_when_not_requested() =
+ suppress_temporary_error_when_already_showing(suppress = false)
+
+ private fun suppress_temporary_error_when_already_showing(suppress: Boolean) = runGenericTest {
+ val errors = listOf("woot", "oh yeah", "nope")
+ val afterSuffix = "(after)"
+ val expectedErrorMessage = if (suppress) errors.first() else errors.last()
+ val messages by collectValues(viewModel.message)
+
+ for (error in errors) {
+ launch {
+ viewModel.showTemporaryError(
+ error,
+ messageAfterError = "$error $afterSuffix",
+ authenticateAfterError = false,
+ suppressIf = { currentMessage -> suppress && currentMessage.isError },
+ )
+ }
+ }
+
+ testScheduler.runCurrent()
+ assertThat(messages)
+ .containsExactly(
+ PromptMessage.Empty,
+ PromptMessage.Error(expectedErrorMessage),
+ )
+ .inOrder()
+
+ testScheduler.advanceUntilIdle()
+ assertThat(messages)
+ .containsExactly(
+ PromptMessage.Empty,
+ PromptMessage.Error(expectedErrorMessage),
+ PromptMessage.Help("$expectedErrorMessage $afterSuffix"),
+ )
+ .inOrder()
+ }
+
+ @Test
+ fun authenticated_at_most_once() = runGenericTest {
val authenticating by collectLastValue(viewModel.isAuthenticating)
val authenticated by collectLastValue(viewModel.isAuthenticated)
@@ -293,7 +404,7 @@
}
@Test
- fun `authenticating cannot restart after authenticated`() = runGenericTest {
+ fun authenticating_cannot_restart_after_authenticated() = runGenericTest {
val authenticating by collectLastValue(viewModel.isAuthenticating)
val authenticated by collectLastValue(viewModel.isAuthenticated)
@@ -309,7 +420,7 @@
}
@Test
- fun `confirm authentication`() = runGenericTest {
+ fun confirm_authentication() = runGenericTest {
val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
viewModel.showAuthenticated(testCase.authenticatedModality, 0)
@@ -341,7 +452,7 @@
}
@Test
- fun `cannot confirm unless authenticated`() = runGenericTest {
+ fun cannot_confirm_unless_authenticated() = runGenericTest {
val authenticating by collectLastValue(viewModel.isAuthenticating)
val authenticated by collectLastValue(viewModel.isAuthenticated)
@@ -360,7 +471,7 @@
}
@Test
- fun `shows help - before authenticated`() = runGenericTest {
+ fun shows_help_before_authenticated() = runGenericTest {
val helpMessage = "please help yourself to some cookies"
val message by collectLastValue(viewModel.message)
val messageVisible by collectLastValue(viewModel.isIndicatorMessageVisible)
@@ -379,7 +490,7 @@
}
@Test
- fun `shows help - after authenticated`() = runGenericTest {
+ fun shows_help_after_authenticated() = runGenericTest {
val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
val helpMessage = "more cookies please"
val authenticating by collectLastValue(viewModel.isAuthenticating)
@@ -409,7 +520,7 @@
}
@Test
- fun `retries after failure`() = runGenericTest {
+ fun retries_after_failure() = runGenericTest {
val errorMessage = "bad"
val helpMessage = "again?"
val expectTryAgainButton = testCase.isFaceOnly
@@ -455,7 +566,7 @@
}
@Test
- fun `switch to credential fallback`() = runGenericTest {
+ fun switch_to_credential_fallback() = runGenericTest {
val size by collectLastValue(viewModel.size)
// TODO(b/251476085): remove Spaghetti, migrate logic, and update this test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
index d09353b..481f36e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractorTest.kt
@@ -19,12 +19,16 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
+import kotlin.math.ceil
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
@@ -65,14 +69,13 @@
@Test
fun pinAuthMethod() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(underTest.message)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice("container1")
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
@@ -98,14 +101,14 @@
@Test
fun pinAuthMethod_tryAutoConfirm_withAutoConfirmPin() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(underTest.message)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice("container1")
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
underTest.clearMessage()
@@ -128,14 +131,13 @@
@Test
fun pinAuthMethod_tryAutoConfirm_withoutAutoConfirmPin() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(underTest.message)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = false)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice("container1")
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.clearMessage()
@@ -153,13 +155,14 @@
@Test
fun passwordAuthMethod() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice("container1")
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PASSWORD)
@@ -185,13 +188,14 @@
@Test
fun patternAuthMethod() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(emptyList())
+ AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice("container1")
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
@@ -204,7 +208,7 @@
// Wrong input.
assertThat(
underTest.authenticate(
- listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(3, 4))
+ listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(1, 2))
)
)
.isFalse()
@@ -215,21 +219,20 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PATTERN)
// Correct input.
- assertThat(underTest.authenticate(emptyList())).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.PATTERN)).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@Test
fun showOrUnlockDevice_notLocked_switchesToGoneScene() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
- underTest.showOrUnlockDevice("container1")
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -237,11 +240,12 @@
@Test
fun showOrUnlockDevice_authMethodNotSecure_switchesToGoneScene() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Swipe)
utils.authenticationRepository.setUnlocked(false)
- underTest.showOrUnlockDevice("container1")
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -249,15 +253,16 @@
@Test
fun showOrUnlockDevice_customMessageShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene("container1"))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(underTest.message)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
val customMessage = "Hello there!"
- underTest.showOrUnlockDevice("container1", customMessage)
+ underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1, customMessage)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
assertThat(message).isEqualTo(customMessage)
@@ -266,67 +271,78 @@
@Test
fun throttling() =
testScope.runTest {
+ val isThrottled by collectLastValue(underTest.isThrottled)
val throttling by collectLastValue(underTest.throttling)
val message by collectLastValue(underTest.message)
val currentScene by
collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
runCurrent()
underTest.showOrUnlockDevice(SceneTestUtils.CONTAINER_1)
runCurrent()
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
- assertThat(throttling).isNull()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
- repeat(BouncerInteractor.THROTTLE_EVERY) { times ->
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) { times ->
// Wrong PIN.
assertThat(underTest.authenticate(listOf(6, 7, 8, 9))).isFalse()
- if (times < BouncerInteractor.THROTTLE_EVERY - 1) {
+ if (
+ times < FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING - 1
+ ) {
assertThat(message).isEqualTo(MESSAGE_WRONG_PIN)
}
}
- assertThat(throttling).isNotNull()
- assertTryAgainMessage(message, BouncerInteractor.THROTTLE_DURATION_SEC)
+ assertThat(isThrottled).isTrue()
+ assertThat(throttling)
+ .isEqualTo(
+ AuthenticationThrottlingModel(
+ failedAttemptCount =
+ FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING,
+ remainingMs = FakeAuthenticationRepository.THROTTLE_DURATION_MS,
+ )
+ )
+ assertTryAgainMessage(
+ message,
+ FakeAuthenticationRepository.THROTTLE_DURATION_MS.milliseconds.inWholeSeconds
+ .toInt()
+ )
// Correct PIN, but throttled, so doesn't change away from the bouncer scene:
- assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isFalse()
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isNull()
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
- assertTryAgainMessage(message, BouncerInteractor.THROTTLE_DURATION_SEC)
+ assertTryAgainMessage(
+ message,
+ FakeAuthenticationRepository.THROTTLE_DURATION_MS.milliseconds.inWholeSeconds
+ .toInt()
+ )
- throttling?.totalDurationSec?.let { seconds ->
+ throttling?.remainingMs?.let { remainingMs ->
+ val seconds = ceil(remainingMs / 1000f).toInt()
repeat(seconds) { time ->
advanceTimeBy(1000)
- val remainingTime = seconds - time - 1
- if (remainingTime > 0) {
- assertTryAgainMessage(message, remainingTime)
+ val remainingTimeSec = seconds - time - 1
+ if (remainingTimeSec > 0) {
+ assertTryAgainMessage(message, remainingTimeSec)
}
}
}
assertThat(message).isEqualTo("")
- assertThat(throttling).isNull()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling)
+ .isEqualTo(
+ AuthenticationThrottlingModel(
+ failedAttemptCount =
+ FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING,
+ )
+ )
assertThat(currentScene?.key).isEqualTo(SceneKey.Bouncer)
// Correct PIN and no longer throttled so changes to the Gone scene:
assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
assertThat(currentScene?.key).isEqualTo(SceneKey.Gone)
- }
-
- @Test
- fun switchesToGone_whenUnlocked() =
- testScope.runTest {
- utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(
- SceneTestUtils.CONTAINER_1,
- SceneModel(SceneKey.Bouncer)
- )
- val currentScene by
- collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
-
- utils.authenticationRepository.setUnlocked(true)
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
}
private fun assertTryAgainMessage(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
index f811ce0..0867558 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModelTest.kt
@@ -55,10 +55,8 @@
@Test
fun animateFailure() =
testScope.runTest {
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
val animateFailure by collectLastValue(underTest.animateFailure)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(animateFailure).isFalse()
// Wrong PIN:
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index 5ffc471..0df0a17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
@@ -18,8 +18,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.google.common.truth.Truth.assertThat
@@ -52,7 +52,10 @@
authenticationInteractor = authenticationInteractor,
sceneInteractor = utils.sceneInteractor(),
)
- private val underTest = utils.bouncerViewModel(bouncerInteractor)
+ private val underTest =
+ utils.bouncerViewModel(
+ bouncerInteractor = bouncerInteractor,
+ )
@Test
fun authMethod_nonNullForSecureMethods_nullForNotSecureMethods() =
@@ -110,18 +113,16 @@
testScope.runTest {
val message by collectLastValue(underTest.message)
val throttling by collectLastValue(bouncerInteractor.throttling)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(message?.isUpdateAnimated).isTrue()
- repeat(BouncerInteractor.THROTTLE_EVERY) {
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) {
// Wrong PIN.
bouncerInteractor.authenticate(listOf(3, 4, 5, 6))
}
assertThat(message?.isUpdateAnimated).isFalse()
- throttling?.totalDurationSec?.let { seconds -> advanceTimeBy(seconds * 1000L) }
+ throttling?.remainingMs?.let { remainingMs -> advanceTimeBy(remainingMs.toLong()) }
assertThat(message?.isUpdateAnimated).isTrue()
}
@@ -135,18 +136,16 @@
}
)
val throttling by collectLastValue(bouncerInteractor.throttling)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(isInputEnabled).isTrue()
- repeat(BouncerInteractor.THROTTLE_EVERY) {
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) {
// Wrong PIN.
bouncerInteractor.authenticate(listOf(3, 4, 5, 6))
}
assertThat(isInputEnabled).isFalse()
- throttling?.totalDurationSec?.let { seconds -> advanceTimeBy(seconds * 1000L) }
+ throttling?.remainingMs?.let { milliseconds -> advanceTimeBy(milliseconds.toLong()) }
assertThat(isInputEnabled).isTrue()
}
@@ -154,11 +153,9 @@
fun throttlingDialogMessage() =
testScope.runTest {
val throttlingDialogMessage by collectLastValue(underTest.throttlingDialogMessage)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
- repeat(BouncerInteractor.THROTTLE_EVERY) {
+ repeat(FakeAuthenticationRepository.MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING) {
// Wrong PIN.
assertThat(throttlingDialogMessage).isNull()
bouncerInteractor.authenticate(listOf(3, 4, 5, 6))
@@ -173,11 +170,9 @@
return listOf(
AuthenticationMethodModel.None,
AuthenticationMethodModel.Swipe,
- AuthenticationMethodModel.Pin(1234),
- AuthenticationMethodModel.Password("password"),
- AuthenticationMethodModel.Pattern(
- listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1))
- ),
+ AuthenticationMethodModel.Pin,
+ AuthenticationMethodModel.Password,
+ AuthenticationMethodModel.Pattern,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index 699571b..b1533fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -72,14 +72,18 @@
@Test
fun onShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -92,14 +96,18 @@
@Test
fun onPasswordInputChanged() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -114,12 +122,16 @@
@Test
fun onAuthenticateKeyPressed_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("password")
@@ -132,14 +144,18 @@
@Test
fun onAuthenticateKeyPressed_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
@@ -154,14 +170,18 @@
@Test
fun onAuthenticateKeyPressed_correctAfterWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val password by collectLastValue(underTest.password)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPasswordInputChanged("wrong")
@@ -180,7 +200,6 @@
}
companion object {
- private const val CONTAINER_NAME = "container1"
private const val ENTER_YOUR_PASSWORD = "Enter your password"
private const val WRONG_PASSWORD = "Wrong password"
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
index 9a1f584..f69cbb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PatternBouncerViewModelTest.kt
@@ -19,6 +19,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
@@ -74,15 +75,19 @@
@Test
fun onShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
+ AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -96,15 +101,19 @@
@Test
fun onDragStart() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
+ AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -120,14 +129,18 @@
@Test
fun onDragEnd_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
+ AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -167,15 +180,19 @@
@Test
fun onDragEnd_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
+ AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -199,15 +216,19 @@
@Test
fun onDragEnd_correctAfterWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val selectedDots by collectLastValue(underTest.selectedDots)
val currentDot by collectLastValue(underTest.currentDot)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pattern(CORRECT_PATTERN)
+ AuthenticationMethodModel.Pattern
)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onDragStart()
@@ -241,20 +262,8 @@
}
companion object {
- private const val CONTAINER_NAME = "container1"
private const val ENTER_YOUR_PATTERN = "Enter your pattern"
private const val WRONG_PATTERN = "Wrong pattern"
- private val CORRECT_PATTERN =
- listOf(
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 1, y = 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 0, y = 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 0, y = 0),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 1, y = 0),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 2, y = 0),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 2, y = 1),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 2, y = 2),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 1, y = 2),
- AuthenticationMethodModel.Pattern.PatternCoordinate(x = 0, y = 2),
- )
+ private val CORRECT_PATTERN = FakeAuthenticationRepository.PATTERN
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
index 608a187..5c6d4c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/PinBouncerViewModelTest.kt
@@ -20,7 +20,6 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
-import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
@@ -54,16 +53,8 @@
sceneInteractor = sceneInteractor,
)
private val bouncerViewModel =
- BouncerViewModel(
- applicationContext = context,
- applicationScope = testScope.backgroundScope,
- interactorFactory =
- object : BouncerInteractor.Factory {
- override fun create(containerName: String): BouncerInteractor {
- return bouncerInteractor
- }
- },
- containerName = CONTAINER_NAME,
+ utils.bouncerViewModel(
+ bouncerInteractor = bouncerInteractor,
)
private val underTest =
PinBouncerViewModel(
@@ -82,11 +73,15 @@
@Test
fun onShown() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -99,14 +94,16 @@
@Test
fun onPinButtonClicked() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -122,14 +119,16 @@
@Test
fun onBackspaceButtonClicked() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -146,13 +145,15 @@
@Test
fun onPinEdit() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val entries by collectLastValue(underTest.pinEntries)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
@@ -172,14 +173,16 @@
@Test
fun onBackspaceButtonLongPressed() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
runCurrent()
@@ -198,12 +201,14 @@
@Test
fun onAuthenticateButtonClicked_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -219,14 +224,16 @@
@Test
fun onAuthenticateButtonClicked_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -245,14 +252,16 @@
@Test
fun onAuthenticateButtonClicked_correctAfterWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -280,12 +289,15 @@
@Test
fun onAutoConfirm_whenCorrect() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -299,14 +311,17 @@
@Test
fun onAutoConfirm_whenWrong() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_NAME))
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
val message by collectLastValue(bouncerViewModel.message)
val entries by collectLastValue(underTest.pinEntries)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
- sceneInteractor.setCurrentScene(CONTAINER_NAME, SceneModel(SceneKey.Bouncer))
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+ sceneInteractor.setCurrentScene(
+ SceneTestUtils.CONTAINER_1,
+ SceneModel(SceneKey.Bouncer)
+ )
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
underTest.onShown()
underTest.onPinButtonClicked(1)
@@ -324,9 +339,7 @@
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = false)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(backspaceButtonAppearance).isEqualTo(ActionButtonAppearance.Shown)
}
@@ -335,9 +348,8 @@
fun backspaceButtonAppearance_withAutoConfirmButNoInput_isHidden() =
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(backspaceButtonAppearance).isEqualTo(ActionButtonAppearance.Hidden)
}
@@ -346,9 +358,8 @@
fun backspaceButtonAppearance_withAutoConfirmAndInput_isShownQuiet() =
testScope.runTest {
val backspaceButtonAppearance by collectLastValue(underTest.backspaceButtonAppearance)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
underTest.onPinButtonClicked(1)
@@ -360,9 +371,7 @@
testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = false)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(confirmButtonAppearance).isEqualTo(ActionButtonAppearance.Shown)
}
@@ -371,9 +380,8 @@
fun confirmButtonAppearance_withAutoConfirm_isHidden() =
testScope.runTest {
val confirmButtonAppearance by collectLastValue(underTest.confirmButtonAppearance)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(confirmButtonAppearance).isEqualTo(ActionButtonAppearance.Hidden)
}
@@ -382,9 +390,8 @@
fun hintedPinLength_withoutAutoConfirm_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = false)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(false)
assertThat(hintedPinLength).isNull()
}
@@ -393,9 +400,8 @@
fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(12345, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(hintedPinLength).isNull()
}
@@ -404,9 +410,9 @@
fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(123456, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+ utils.authenticationRepository.overrideCredential(listOf(1, 2, 3, 4, 5, 6))
assertThat(hintedPinLength).isEqualTo(6)
}
@@ -415,15 +421,13 @@
fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() =
testScope.runTest {
val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234567, autoConfirm = true)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
assertThat(hintedPinLength).isNull()
}
companion object {
- private const val CONTAINER_NAME = "container1"
private const val ENTER_YOUR_PIN = "Enter your pin"
private const val WRONG_PIN = "Wrong pin"
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
index 4210675..71d2ec1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsEditingActivityTest.kt
@@ -11,9 +11,9 @@
import android.window.OnBackInvokedDispatcher
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.flags.FakeFeatureFlags
@@ -63,24 +63,19 @@
@JvmField
var activityRule =
ActivityTestRule(
- object :
- SingleActivityFactory<TestableControlsEditingActivity>(
- TestableControlsEditingActivity::class.java
- ) {
- override fun create(intent: Intent?): TestableControlsEditingActivity {
- return TestableControlsEditingActivity(
- featureFlags,
- uiExecutor,
- controller,
- userTracker,
- customIconCache,
- mockDispatcher,
- latch
- )
- }
+ /* activityFactory= */ SingleActivityFactory {
+ TestableControlsEditingActivity(
+ featureFlags,
+ uiExecutor,
+ controller,
+ userTracker,
+ customIconCache,
+ mockDispatcher,
+ latch
+ )
},
- false,
- false
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
)
@Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
index f4cc8bc..f11c296 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
@@ -13,9 +13,9 @@
import androidx.test.filters.FlakyTest
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
@@ -91,24 +91,19 @@
@JvmField
var activityRule =
ActivityTestRule(
- object :
- SingleActivityFactory<TestableControlsFavoritingActivity>(
- TestableControlsFavoritingActivity::class.java
- ) {
- override fun create(intent: Intent?): TestableControlsFavoritingActivity {
- return TestableControlsFavoritingActivity(
- featureFlags,
- executor,
- controller,
- listingController,
- userTracker,
- mockDispatcher,
- latch
- )
- }
+ /* activityFactory= */ SingleActivityFactory {
+ TestableControlsFavoritingActivity(
+ featureFlags,
+ executor,
+ controller,
+ listingController,
+ userTracker,
+ mockDispatcher,
+ latch
+ )
},
- false,
- false
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
)
@Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
index 4ba6718..d17495f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsProviderSelectorActivityTest.kt
@@ -29,8 +29,8 @@
import android.window.OnBackInvokedDispatcher
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
@@ -91,26 +91,21 @@
@JvmField
var activityRule =
ActivityTestRule(
- object :
- SingleActivityFactory<TestableControlsProviderSelectorActivity>(
- TestableControlsProviderSelectorActivity::class.java
- ) {
- override fun create(intent: Intent?): TestableControlsProviderSelectorActivity {
- return TestableControlsProviderSelectorActivity(
- executor,
- backExecutor,
- listingController,
- controlsController,
- userTracker,
- authorizedPanelsRepository,
- dialogFactory,
- mockDispatcher,
- latch
- )
- }
+ /* activityFactory= */ SingleActivityFactory {
+ TestableControlsProviderSelectorActivity(
+ executor,
+ backExecutor,
+ listingController,
+ controlsController,
+ userTracker,
+ authorizedPanelsRepository,
+ dialogFactory,
+ mockDispatcher,
+ latch
+ )
},
- false,
- false
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
)
@Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
index 314b176..ca970bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
@@ -30,8 +30,8 @@
import androidx.lifecycle.Lifecycle
import androidx.test.filters.MediumTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.settings.UserTracker
@@ -81,19 +81,18 @@
@Rule
@JvmField
- var activityRule = ActivityTestRule<TestControlsRequestDialog>(
- object : SingleActivityFactory<TestControlsRequestDialog>(
- TestControlsRequestDialog::class.java
- ) {
- override fun create(intent: Intent?): TestControlsRequestDialog {
- return TestControlsRequestDialog(
- mainExecutor,
- controller,
- userTracker,
- listingController
- )
- }
- }, false, false)
+ var activityRule = ActivityTestRule(
+ /* activityFactory= */ SingleActivityFactory {
+ TestControlsRequestDialog(
+ mainExecutor,
+ controller,
+ userTracker,
+ listingController
+ )
+ },
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
+ )
private lateinit var control: Control
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
index 2d3e10e..e279d28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsActivityTest.kt
@@ -23,8 +23,8 @@
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.settings.ControlsSettingsDialogManager
import com.android.systemui.flags.FeatureFlags
@@ -53,23 +53,18 @@
@JvmField
var activityRule =
ActivityTestRule(
- object :
- SingleActivityFactory<TestableControlsActivity>(
- TestableControlsActivity::class.java
- ) {
- override fun create(intent: Intent?): TestableControlsActivity {
- return TestableControlsActivity(
- uiController,
- broadcastDispatcher,
- dreamManager,
- featureFlags,
- controlsSettingsDialogManager,
- keyguardStateController,
- )
- }
+ /* activityFactory= */ SingleActivityFactory {
+ TestableControlsActivity(
+ uiController,
+ broadcastDispatcher,
+ dreamManager,
+ featureFlags,
+ controlsSettingsDialogManager,
+ keyguardStateController,
+ )
},
- false,
- false
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
)
@Before
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
index 7840525..021facc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/PanelTaskViewControllerTest.kt
@@ -146,17 +146,8 @@
}
@Test
- fun testTaskViewReleasedOnDismiss() {
- underTest.dismiss()
- verify(taskView).release()
- }
-
- @Test
- fun testTaskViewReleasedOnBackOnRoot() {
- underTest.launchTaskView()
- verify(taskView).setListener(any(), capture(listenerCaptor))
-
- listenerCaptor.value.onBackPressedOnTaskRoot(0)
+ fun testTaskViewReleasedOnRelease() {
+ underTest.release()
verify(taskView).release()
}
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 3383516..e73d580 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/CustomizationProviderTest.kt
@@ -175,7 +175,6 @@
)
val featureFlags =
FakeFeatureFlags().apply {
- set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
set(Flags.REVAMPED_WALLPAPER_UI, true)
set(Flags.WALLPAPER_FULLSCREEN_PREVIEW, true)
@@ -191,7 +190,6 @@
bouncerRepository = FakeKeyguardBouncerRepository(),
configurationRepository = FakeConfigurationRepository(),
),
- registry = mock(),
lockPatternUtils = lockPatternUtils,
keyguardStateController = keyguardStateController,
userTracker = userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 729a1cc..ce8028c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -19,6 +19,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
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;
@@ -31,6 +32,7 @@
import android.media.MediaMetadata;
import android.media.session.PlaybackState;
import android.net.Uri;
+import android.os.Handler;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -166,6 +168,7 @@
@Test
public void updatesClock() {
+ clearInvocations(mContentResolver);
mProvider.mKeyguardUpdateMonitorCallback.onTimeChanged();
TestableLooper.get(this).processAllMessages();
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
@@ -217,11 +220,13 @@
reset(mContentResolver);
mProvider.onPrimaryMetadataOrStateChanged(mock(MediaMetadata.class),
PlaybackState.STATE_PLAYING);
+ TestableLooper.get(this).processAllMessages();
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
// Hides after waking up
reset(mContentResolver);
mProvider.onDozingChanged(false);
+ TestableLooper.get(this).processAllMessages();
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
}
@@ -231,6 +236,7 @@
mProvider.onPrimaryMetadataOrStateChanged(mock(MediaMetadata.class),
PlaybackState.STATE_PLAYING);
reset(mContentResolver);
+ TestableLooper.get(this).processAllMessages();
// Show media when dozing
mProvider.onDozingChanged(true);
verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
@@ -272,6 +278,8 @@
mMediaManager = KeyguardSliceProviderTest.this.mNotificationMediaManager;
mKeyguardUpdateMonitor = KeyguardSliceProviderTest.this.mKeyguardUpdateMonitor;
mUserTracker = KeyguardSliceProviderTest.this.mUserTracker;
+ mBgHandler =
+ new Handler(TestableLooper.get(KeyguardSliceProviderTest.this).getLooper());
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
index f243d7b..df1833e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/MuteQuickAffordanceCoreStartableTest.kt
@@ -24,8 +24,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
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.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
@@ -59,8 +57,6 @@
class MuteQuickAffordanceCoreStartableTest : SysuiTestCase() {
@Mock
- private lateinit var featureFlags: FeatureFlags
- @Mock
private lateinit var userTracker: UserTracker
@Mock
private lateinit var ringerModeTracker: RingerModeTracker
@@ -78,8 +74,6 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)).thenReturn(true)
-
val config: KeyguardQuickAffordanceConfig = mock()
whenever(config.key).thenReturn(BuiltInKeyguardQuickAffordanceKeys.MUTE)
@@ -90,7 +84,6 @@
testScope = TestScope(testDispatcher)
underTest = MuteQuickAffordanceCoreStartable(
- featureFlags,
userTracker,
ringerModeTracker,
userFileManager,
@@ -101,20 +94,7 @@
}
@Test
- fun featureFlagIsOFF_doNothingWithKeyguardQuickAffordanceRepository() = testScope.runTest {
- //given
- whenever(featureFlags.isEnabled(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES)).thenReturn(false)
-
- //when
- underTest.start()
-
- //then
- verifyZeroInteractions(keyguardQuickAffordanceRepository)
- coroutineContext.cancelChildren()
- }
-
- @Test
- fun featureFlagIsON_callToKeyguardQuickAffordanceRepository() = testScope.runTest {
+ fun callToKeyguardQuickAffordanceRepository() = testScope.runTest {
//given
val ringerModeInternal = mock<MutableLiveData<Int>>()
whenever(ringerModeTracker.ringerModeInternal).thenReturn(ringerModeInternal)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index d62db5d..020c0b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -228,6 +228,7 @@
bypassControllerOverride,
testScope.backgroundScope,
testDispatcher,
+ testDispatcher,
sessionTracker,
uiEventLogger,
FaceAuthenticationLogger(logcatLogBuffer("DeviceEntryFaceAuthRepositoryLog")),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 25573de..e9f0d56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -299,6 +299,16 @@
}
@Test
+ fun isActiveDreamLockscreenHosted() =
+ testScope.runTest {
+ underTest.setIsActiveDreamLockscreenHosted(true)
+ assertThat(underTest.isActiveDreamLockscreenHosted.value).isEqualTo(true)
+
+ underTest.setIsActiveDreamLockscreenHosted(false)
+ assertThat(underTest.isActiveDreamLockscreenHosted.value).isEqualTo(false)
+ }
+
+ @Test
fun wakefulness() =
testScope.runTest {
val values = mutableListOf<WakefulnessModel>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index 8540bf7..3858cfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -40,7 +40,6 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
-import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
import com.android.systemui.plugins.ActivityStarter
@@ -300,7 +299,6 @@
)
val featureFlags =
FakeFeatureFlags().apply {
- set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
set(Flags.FACE_AUTH_REFACTOR, true)
}
val testDispatcher = StandardTestDispatcher()
@@ -312,20 +310,6 @@
featureFlags = featureFlags,
)
.keyguardInteractor,
- registry =
- FakeKeyguardQuickAffordanceRegistry(
- mapOf(
- KeyguardQuickAffordancePosition.BOTTOM_START to
- listOf(
- homeControls,
- ),
- KeyguardQuickAffordancePosition.BOTTOM_END to
- listOf(
- quickAccessWallet,
- qrCodeScanner,
- ),
- ),
- ),
lockPatternUtils = lockPatternUtils,
keyguardStateController = keyguardStateController,
userTracker = userTracker,
@@ -345,6 +329,7 @@
@Test
fun onQuickAffordanceTriggered() =
testScope.runTest {
+ val key = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS
setUpMocks(
needStrongAuthAfterBoot = needStrongAuthAfterBoot,
keyguardIsUnlocked = keyguardIsUnlocked,
@@ -367,7 +352,7 @@
}
underTest.onQuickAffordanceTriggered(
- configKey = BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
+ configKey = "${KeyguardQuickAffordancePosition.BOTTOM_START.toSlotId()}::${key}",
expandable = expandable,
slotId = "",
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index a0c5a75..07caf59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -44,7 +44,6 @@
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
-import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
@@ -102,6 +101,15 @@
MockitoAnnotations.initMocks(this)
overrideResource(R.bool.custom_lockscreen_shortcuts_enabled, true)
+ overrideResource(
+ R.array.config_keyguardQuickAffordanceDefaults,
+ arrayOf(
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + ":" +
+ BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + ":" +
+ BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
+ )
+ )
repository = FakeKeyguardRepository()
repository.setKeyguardShowing(true)
@@ -164,7 +172,6 @@
)
featureFlags =
FakeFeatureFlags().apply {
- set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
set(Flags.FACE_AUTH_REFACTOR, true)
}
@@ -176,20 +183,6 @@
underTest =
KeyguardQuickAffordanceInteractor(
keyguardInteractor = withDeps.keyguardInteractor,
- registry =
- FakeKeyguardQuickAffordanceRegistry(
- mapOf(
- KeyguardQuickAffordancePosition.BOTTOM_START to
- listOf(
- homeControls,
- ),
- KeyguardQuickAffordancePosition.BOTTOM_END to
- listOf(
- quickAccessWallet,
- qrCodeScanner,
- ),
- ),
- ),
lockPatternUtils = lockPatternUtils,
keyguardStateController = keyguardStateController,
userTracker = userTracker,
@@ -225,7 +218,9 @@
assertThat(collectedValue())
.isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible
- assertThat(visibleModel.configKey).isEqualTo(configKey)
+ assertThat(visibleModel.configKey).isEqualTo(
+ "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${configKey}"
+ )
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
@@ -250,7 +245,9 @@
assertThat(collectedValue())
.isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible
- assertThat(visibleModel.configKey).isEqualTo(configKey)
+ assertThat(visibleModel.configKey).isEqualTo(
+ "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END}::${configKey}"
+ )
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
@@ -387,7 +384,9 @@
assertThat(collectedValue())
.isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
val visibleModel = collectedValue() as KeyguardQuickAffordanceModel.Visible
- assertThat(visibleModel.configKey).isEqualTo(configKey)
+ assertThat(visibleModel.configKey).isEqualTo(
+ "${KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START}::${configKey}"
+ )
assertThat(visibleModel.icon).isEqualTo(ICON)
assertThat(visibleModel.icon.contentDescription)
.isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
@@ -401,8 +400,6 @@
R.array.config_keyguardQuickAffordanceDefaults,
arrayOf<String>(),
)
-
- featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
homeControls.setState(
KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON)
)
@@ -543,7 +540,6 @@
@Test
fun unselect_one() =
testScope.runTest {
- featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
homeControls.setState(
KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON)
)
@@ -620,7 +616,6 @@
@Test
fun useLongPress_whenDocked_isFalse() =
testScope.runTest {
- featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
dockManager.setIsDocked(true)
val useLongPress by collectLastValue(underTest.useLongPress())
@@ -631,7 +626,6 @@
@Test
fun useLongPress_whenNotDocked_isTrue() =
testScope.runTest {
- featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
dockManager.setIsDocked(false)
val useLongPress by collectLastValue(underTest.useLongPress())
@@ -642,7 +636,6 @@
@Test
fun useLongPress_whenNotDocked_isTrue_changedTo_whenDocked_isFalse() =
testScope.runTest {
- featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
dockManager.setIsDocked(false)
val firstUseLongPress by collectLastValue(underTest.useLongPress())
runCurrent()
@@ -660,7 +653,6 @@
@Test
fun unselect_all() =
testScope.runTest {
- featureFlags.set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
homeControls.setState(
KeyguardQuickAffordanceConfig.LockScreenState.Visible(icon = ICON)
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
index abbdc3d..ca6a5b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LockscreenSceneInteractorTest.kt
@@ -47,7 +47,6 @@
private val underTest =
utils.lockScreenSceneInteractor(
authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
bouncerInteractor =
utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
@@ -94,9 +93,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
utils.authenticationRepository.setUnlocked(false)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -109,9 +106,7 @@
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
utils.authenticationRepository.setUnlocked(true)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
underTest.dismissLockscreen()
@@ -133,29 +128,11 @@
}
@Test
- fun deviceLockedInNonLockScreenScene_switchesToLockScreenScene() =
- testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- runCurrent()
- sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
- runCurrent()
- utils.authenticationRepository.setUnlocked(true)
- runCurrent()
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
-
- utils.authenticationRepository.setUnlocked(false)
-
- assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- }
-
- @Test
fun switchFromLockScreenToGone_authMethodNotSwipe_doesNotUnlockDevice() =
testScope.runTest {
val isUnlocked by collectLastValue(authenticationInteractor.isUnlocked)
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Lockscreen))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
assertThat(isUnlocked).isFalse()
sceneInteractor.setCurrentScene(CONTAINER_1, SceneModel(SceneKey.Gone))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.kt
deleted file mode 100644
index 13e2768..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/FakeKeyguardQuickAffordanceRegistry.kt
+++ /dev/null
@@ -1,40 +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.keyguard.domain.quickaffordance
-
-import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
-import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
-
-/** Fake implementation of [FakeKeyguardQuickAffordanceRegistry], for tests. */
-class FakeKeyguardQuickAffordanceRegistry(
- private val configsByPosition:
- Map<KeyguardQuickAffordancePosition, List<FakeKeyguardQuickAffordanceConfig>>,
-) : KeyguardQuickAffordanceRegistry<FakeKeyguardQuickAffordanceConfig> {
-
- override fun getAll(
- position: KeyguardQuickAffordancePosition
- ): List<FakeKeyguardQuickAffordanceConfig> {
- return configsByPosition.getValue(position)
- }
-
- override fun get(
- key: String,
- ): FakeKeyguardQuickAffordanceConfig {
- return configsByPosition.values.flatten().associateBy { config -> config.key }.getValue(key)
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index d02b3fc..06bf7f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
@@ -47,7 +48,6 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardLongPressInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
-import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger
@@ -102,7 +102,6 @@
private lateinit var testScope: TestScope
private lateinit var repository: FakeKeyguardRepository
- private lateinit var registry: FakeKeyguardQuickAffordanceRegistry
private lateinit var homeControlsQuickAffordanceConfig: FakeKeyguardQuickAffordanceConfig
private lateinit var quickAccessWalletAffordanceConfig: FakeKeyguardQuickAffordanceConfig
private lateinit var qrCodeScannerAffordanceConfig: FakeKeyguardQuickAffordanceConfig
@@ -112,6 +111,18 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+
+ overrideResource(R.bool.custom_lockscreen_shortcuts_enabled, true)
+ overrideResource(
+ R.array.config_keyguardQuickAffordanceDefaults,
+ arrayOf(
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START + ":" +
+ BuiltInKeyguardQuickAffordanceKeys.HOME_CONTROLS,
+ KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END + ":" +
+ BuiltInKeyguardQuickAffordanceKeys.QUICK_ACCESS_WALLET
+ )
+ )
+
whenever(burnInHelperWrapper.burnInOffset(anyInt(), any()))
.thenReturn(RETURNED_BURN_IN_OFFSET)
@@ -125,23 +136,8 @@
FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
dockManager = DockManagerFake()
biometricSettingsRepository = FakeBiometricSettingsRepository()
- registry =
- FakeKeyguardQuickAffordanceRegistry(
- mapOf(
- KeyguardQuickAffordancePosition.BOTTOM_START to
- listOf(
- homeControlsQuickAffordanceConfig,
- ),
- KeyguardQuickAffordancePosition.BOTTOM_END to
- listOf(
- quickAccessWalletAffordanceConfig,
- qrCodeScannerAffordanceConfig,
- ),
- ),
- )
val featureFlags =
FakeFeatureFlags().apply {
- set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, false)
set(Flags.FACE_AUTH_REFACTOR, true)
set(Flags.LOCK_SCREEN_LONG_PRESS_ENABLED, false)
set(Flags.LOCK_SCREEN_LONG_PRESS_DIRECT_TO_WPP, false)
@@ -152,7 +148,6 @@
repository = withDeps.repository
whenever(userTracker.userHandle).thenReturn(mock())
- whenever(userTracker.userId).thenReturn(10)
whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
.thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED)
val testDispatcher = StandardTestDispatcher()
@@ -225,7 +220,6 @@
quickAffordanceInteractor =
KeyguardQuickAffordanceInteractor(
keyguardInteractor = keyguardInteractor,
- registry = registry,
lockPatternUtils = lockPatternUtils,
keyguardStateController = keyguardStateController,
userTracker = userTracker,
@@ -700,7 +694,8 @@
KeyguardQuickAffordanceConfig.LockScreenState.Hidden
}
config.setState(lockScreenState)
- return config.key
+
+ return "${position.toSlotId()}::${config.key}"
}
private fun assertQuickAffordanceViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index ff4ec4b..ba8e0f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -56,7 +56,6 @@
override fun create(containerName: String): LockscreenSceneInteractor {
return utils.lockScreenSceneInteractor(
authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
bouncerInteractor =
utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
@@ -73,7 +72,7 @@
testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(false)
@@ -86,7 +85,7 @@
testScope.runTest {
val lockButtonIcon by collectLastValue(underTest.lockButtonIcon)
utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Password("password")
+ AuthenticationMethodModel.Password
)
utils.authenticationRepository.setUnlocked(true)
@@ -108,9 +107,7 @@
fun upTransitionSceneKey_swipeToUnlockedNotEnabled_bouncer() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Bouncer)
@@ -120,9 +117,7 @@
fun onLockButtonClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -135,9 +130,7 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -150,9 +143,7 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
@@ -165,9 +156,7 @@
fun onLockButtonClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index 56698e0..d1299d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -261,7 +261,6 @@
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(SMARTSPACE_CREATION_TIME)
whenever(mediaSmartspaceTarget.expiryTimeMillis).thenReturn(SMARTSPACE_EXPIRY_TIME)
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
- whenever(mediaFlags.isExplicitIndicatorEnabled()).thenReturn(true)
whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false)
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
whenever(mediaFlags.isRemoteResumeAllowed()).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index f902be3..b4b3073 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -233,7 +233,6 @@
FakeFeatureFlags().apply {
this.set(Flags.UMO_SURFACE_RIPPLE, false)
this.set(Flags.UMO_TURBULENCE_NOISE, false)
- this.set(Flags.MEDIA_EXPLICIT_INDICATOR, true)
this.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, false)
}
@Mock private lateinit var globalSettings: GlobalSettings
@@ -1793,7 +1792,7 @@
// THEN it sends the PendingIntent without dismissing keyguard first,
// and does not use the Intent directly (see b/271845008)
captor.value.onClick(viewHolder.player)
- verify(pendingIntent).send()
+ verify(pendingIntent).send(any(Bundle::class.java))
verify(pendingIntent, never()).getIntent()
verify(activityStarter, never()).postStartActivityDismissingKeyguard(eq(clickIntent), any())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt
index 36b913f..bdb095a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt
@@ -22,9 +22,9 @@
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.Companion.ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.util.mockito.any
@@ -47,13 +47,9 @@
@Rule
@JvmField
val activityRule =
- ActivityTestRule<LaunchNotesRoleSettingsTrampolineActivity>(
- /* activityFactory= */ object :
- SingleActivityFactory<LaunchNotesRoleSettingsTrampolineActivity>(
- LaunchNotesRoleSettingsTrampolineActivity::class.java
- ) {
- override fun create(intent: Intent?) =
- LaunchNotesRoleSettingsTrampolineActivity(noteTaskController)
+ ActivityTestRule(
+ /* activityFactory= */ SingleActivityFactory {
+ LaunchNotesRoleSettingsTrampolineActivity(noteTaskController)
},
/* initialTouchMode= */ false,
/* launchActivity= */ false,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt
index 627c4a8..1f0f0d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt
@@ -16,14 +16,13 @@
package com.android.systemui.notetask.shortcut
-import android.content.Intent
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
import com.android.systemui.util.mockito.any
@@ -47,12 +46,8 @@
@JvmField
val activityRule =
ActivityTestRule<LaunchNoteTaskActivity>(
- /* activityFactory= */ object :
- SingleActivityFactory<LaunchNoteTaskActivity>(LaunchNoteTaskActivity::class.java) {
- override fun create(intent: Intent?) =
- LaunchNoteTaskActivity(
- controller = noteTaskController,
- )
+ /* activityFactory= */ SingleActivityFactory {
+ LaunchNoteTaskActivity(controller = noteTaskController)
},
/* initialTouchMode= */ false,
/* launchActivity= */ false,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index c85c8ba..ed7a59e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -53,7 +53,6 @@
override fun create(containerName: String): LockscreenSceneInteractor {
return utils.lockScreenSceneInteractor(
authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
bouncerInteractor =
utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
@@ -69,9 +68,7 @@
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -84,9 +81,7 @@
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index de15c77..9ce378d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.scene.shared.model.SceneTransitionModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
@@ -40,7 +41,7 @@
@Test
fun allSceneKeys() {
val underTest = utils.fakeSceneContainerRepository()
- assertThat(underTest.allSceneKeys("container1"))
+ assertThat(underTest.allSceneKeys(SceneTestUtils.CONTAINER_1))
.isEqualTo(
listOf(
SceneKey.QuickSettings,
@@ -61,10 +62,10 @@
@Test
fun currentScene() = runTest {
val underTest = utils.fakeSceneContainerRepository()
- val currentScene by collectLastValue(underTest.currentScene("container1"))
+ val currentScene by collectLastValue(underTest.currentScene(SceneTestUtils.CONTAINER_1))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene("container1", SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@@ -85,26 +86,26 @@
val underTest =
utils.fakeSceneContainerRepository(
setOf(
- utils.fakeSceneContainerConfig("container1"),
+ utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
utils.fakeSceneContainerConfig(
- "container2",
+ SceneTestUtils.CONTAINER_2,
listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
),
)
)
- underTest.setCurrentScene("container2", SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneTestUtils.CONTAINER_2, SceneModel(SceneKey.Shade))
}
@Test
fun isVisible() = runTest {
val underTest = utils.fakeSceneContainerRepository()
- val isVisible by collectLastValue(underTest.isVisible("container1"))
+ val isVisible by collectLastValue(underTest.isVisible(SceneTestUtils.CONTAINER_1))
assertThat(isVisible).isTrue()
- underTest.setVisible("container1", false)
+ underTest.setVisible(SceneTestUtils.CONTAINER_1, false)
assertThat(isVisible).isFalse()
- underTest.setVisible("container1", true)
+ underTest.setVisible(SceneTestUtils.CONTAINER_1, true)
assertThat(isVisible).isTrue()
}
@@ -124,13 +125,13 @@
fun sceneTransitionProgress() = runTest {
val underTest = utils.fakeSceneContainerRepository()
val sceneTransitionProgress by
- collectLastValue(underTest.sceneTransitionProgress("container1"))
+ collectLastValue(underTest.sceneTransitionProgress(SceneTestUtils.CONTAINER_1))
assertThat(sceneTransitionProgress).isEqualTo(1f)
- underTest.setSceneTransitionProgress("container1", 0.1f)
+ underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.1f)
assertThat(sceneTransitionProgress).isEqualTo(0.1f)
- underTest.setSceneTransitionProgress("container1", 0.9f)
+ underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.9f)
assertThat(sceneTransitionProgress).isEqualTo(0.9f)
}
@@ -139,4 +140,75 @@
val underTest = utils.fakeSceneContainerRepository()
underTest.sceneTransitionProgress("nonExistingContainer")
}
+
+ @Test
+ fun setSceneTransition() = runTest {
+ val underTest =
+ utils.fakeSceneContainerRepository(
+ setOf(
+ utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
+ utils.fakeSceneContainerConfig(
+ SceneTestUtils.CONTAINER_2,
+ listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
+ ),
+ )
+ )
+ val sceneTransition by
+ collectLastValue(underTest.sceneTransitions(SceneTestUtils.CONTAINER_2))
+ assertThat(sceneTransition).isNull()
+
+ underTest.setSceneTransition(
+ SceneTestUtils.CONTAINER_2,
+ SceneKey.Lockscreen,
+ SceneKey.QuickSettings
+ )
+ assertThat(sceneTransition)
+ .isEqualTo(
+ SceneTransitionModel(from = SceneKey.Lockscreen, to = SceneKey.QuickSettings)
+ )
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun setSceneTransition_noSuchContainer_throws() {
+ val underTest = utils.fakeSceneContainerRepository()
+ underTest.setSceneTransition("nonExistingContainer", SceneKey.Lockscreen, SceneKey.Shade)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun setSceneTransition_noFromSceneInContainer_throws() {
+ val underTest =
+ utils.fakeSceneContainerRepository(
+ setOf(
+ utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
+ utils.fakeSceneContainerConfig(
+ SceneTestUtils.CONTAINER_2,
+ listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
+ ),
+ )
+ )
+ underTest.setSceneTransition(
+ SceneTestUtils.CONTAINER_2,
+ SceneKey.Shade,
+ SceneKey.Lockscreen
+ )
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun setSceneTransition_noToSceneInContainer_throws() {
+ val underTest =
+ utils.fakeSceneContainerRepository(
+ setOf(
+ utils.fakeSceneContainerConfig(SceneTestUtils.CONTAINER_1),
+ utils.fakeSceneContainerConfig(
+ SceneTestUtils.CONTAINER_2,
+ listOf(SceneKey.QuickSettings, SceneKey.Lockscreen)
+ ),
+ )
+ )
+ underTest.setSceneTransition(
+ SceneTestUtils.CONTAINER_2,
+ SceneKey.Shade,
+ SceneKey.Lockscreen
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index ee4f6c2..3050c4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.scene.SceneTestUtils
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.scene.shared.model.SceneTransitionModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
@@ -40,36 +41,63 @@
@Test
fun allSceneKeys() {
- assertThat(underTest.allSceneKeys("container1")).isEqualTo(utils.fakeSceneKeys())
+ assertThat(underTest.allSceneKeys(SceneTestUtils.CONTAINER_1))
+ .isEqualTo(utils.fakeSceneKeys())
}
@Test
- fun sceneTransitions() = runTest {
- val currentScene by collectLastValue(underTest.currentScene("container1"))
+ fun currentScene() = runTest {
+ val currentScene by collectLastValue(underTest.currentScene(SceneTestUtils.CONTAINER_1))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Lockscreen))
- underTest.setCurrentScene("container1", SceneModel(SceneKey.Shade))
+ underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade))
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Shade))
}
@Test
fun sceneTransitionProgress() = runTest {
- val progress by collectLastValue(underTest.sceneTransitionProgress("container1"))
+ val progress by
+ collectLastValue(underTest.sceneTransitionProgress(SceneTestUtils.CONTAINER_1))
assertThat(progress).isEqualTo(1f)
- underTest.setSceneTransitionProgress("container1", 0.55f)
+ underTest.setSceneTransitionProgress(SceneTestUtils.CONTAINER_1, 0.55f)
assertThat(progress).isEqualTo(0.55f)
}
@Test
fun isVisible() = runTest {
- val isVisible by collectLastValue(underTest.isVisible("container1"))
+ val isVisible by collectLastValue(underTest.isVisible(SceneTestUtils.CONTAINER_1))
assertThat(isVisible).isTrue()
- underTest.setVisible("container1", false)
+ underTest.setVisible(SceneTestUtils.CONTAINER_1, false)
assertThat(isVisible).isFalse()
- underTest.setVisible("container1", true)
+ underTest.setVisible(SceneTestUtils.CONTAINER_1, true)
assertThat(isVisible).isTrue()
}
+
+ @Test
+ fun sceneTransitions() = runTest {
+ val transitions by collectLastValue(underTest.sceneTransitions(SceneTestUtils.CONTAINER_1))
+ assertThat(transitions).isNull()
+
+ val initialSceneKey = underTest.currentScene(SceneTestUtils.CONTAINER_1).value.key
+ underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.Shade))
+ assertThat(transitions)
+ .isEqualTo(
+ SceneTransitionModel(
+ from = initialSceneKey,
+ to = SceneKey.Shade,
+ )
+ )
+
+ underTest.setCurrentScene(SceneTestUtils.CONTAINER_1, SceneModel(SceneKey.QuickSettings))
+ assertThat(transitions)
+ .isEqualTo(
+ SceneTransitionModel(
+ from = SceneKey.Shade,
+ to = SceneKey.QuickSettings,
+ )
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt
new file mode 100644
index 0000000..df5e7bc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.domain.startable
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.Flags
+import com.android.systemui.scene.SceneTestUtils
+import com.android.systemui.scene.shared.model.SceneContainerNames
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.SceneModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class SystemUiDefaultSceneContainerStartableTest : SysuiTestCase() {
+
+ private val utils = SceneTestUtils(this)
+ private val testScope = utils.testScope
+ private val sceneInteractor = utils.sceneInteractor()
+ private val featureFlags = utils.featureFlags
+ private val authenticationRepository = utils.authenticationRepository()
+ private val authenticationInteractor =
+ utils.authenticationInteractor(
+ repository = authenticationRepository,
+ )
+
+ private val underTest =
+ SystemUiDefaultSceneContainerStartable(
+ applicationScope = testScope.backgroundScope,
+ sceneInteractor = sceneInteractor,
+ authenticationInteractor = authenticationInteractor,
+ featureFlags = featureFlags,
+ )
+
+ @Before
+ fun setUp() {
+ prepareState()
+ }
+
+ @Test
+ fun hydrateVisibility_featureEnabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ val isVisible by
+ collectLastValue(sceneInteractor.isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT))
+ prepareState(
+ isFeatureEnabled = true,
+ isDeviceUnlocked = true,
+ initialSceneKey = SceneKey.Gone,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ assertThat(isVisible).isTrue()
+
+ underTest.start()
+
+ assertThat(isVisible).isFalse()
+
+ sceneInteractor.setCurrentScene(
+ SceneContainerNames.SYSTEM_UI_DEFAULT,
+ SceneModel(SceneKey.Shade)
+ )
+ assertThat(isVisible).isTrue()
+ }
+
+ @Test
+ fun hydrateVisibility_featureDisabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ val isVisible by
+ collectLastValue(sceneInteractor.isVisible(SceneContainerNames.SYSTEM_UI_DEFAULT))
+ prepareState(
+ isFeatureEnabled = false,
+ isDeviceUnlocked = true,
+ initialSceneKey = SceneKey.Lockscreen,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ assertThat(isVisible).isTrue()
+
+ underTest.start()
+ assertThat(isVisible).isTrue()
+
+ sceneInteractor.setCurrentScene(
+ SceneContainerNames.SYSTEM_UI_DEFAULT,
+ SceneModel(SceneKey.Gone)
+ )
+ assertThat(isVisible).isTrue()
+
+ sceneInteractor.setCurrentScene(
+ SceneContainerNames.SYSTEM_UI_DEFAULT,
+ SceneModel(SceneKey.Shade)
+ )
+ assertThat(isVisible).isTrue()
+ }
+
+ @Test
+ fun switchToLockscreenWhenDeviceLocks_featureEnabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = true,
+ isDeviceUnlocked = true,
+ initialSceneKey = SceneKey.Gone,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ underTest.start()
+
+ authenticationRepository.setUnlocked(false)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ }
+
+ @Test
+ fun switchToLockscreenWhenDeviceLocks_featureDisabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = false,
+ isDeviceUnlocked = false,
+ initialSceneKey = SceneKey.Gone,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ underTest.start()
+
+ authenticationRepository.setUnlocked(false)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ }
+
+ @Test
+ fun switchFromBouncerToGoneWhenDeviceUnlocked_featureEnabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = true,
+ isDeviceUnlocked = false,
+ initialSceneKey = SceneKey.Bouncer,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Bouncer)
+ underTest.start()
+
+ authenticationRepository.setUnlocked(true)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ }
+
+ @Test
+ fun switchFromBouncerToGoneWhenDeviceUnlocked_featureDisabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = false,
+ isDeviceUnlocked = false,
+ initialSceneKey = SceneKey.Bouncer,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Bouncer)
+ underTest.start()
+
+ authenticationRepository.setUnlocked(true)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Bouncer)
+ }
+
+ @Test
+ fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOn() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = true,
+ isBypassEnabled = true,
+ initialSceneKey = SceneKey.Lockscreen,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ underTest.start()
+
+ authenticationRepository.setUnlocked(true)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ }
+
+ @Test
+ fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOn_bypassOff() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = true,
+ isBypassEnabled = false,
+ initialSceneKey = SceneKey.Lockscreen,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ underTest.start()
+
+ authenticationRepository.setUnlocked(true)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ }
+
+ @Test
+ fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn_featureOff_bypassOn() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = false,
+ isBypassEnabled = true,
+ initialSceneKey = SceneKey.Lockscreen,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ underTest.start()
+
+ authenticationRepository.setUnlocked(true)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ }
+
+ private fun prepareState(
+ isFeatureEnabled: Boolean = true,
+ isDeviceUnlocked: Boolean = false,
+ isBypassEnabled: Boolean = false,
+ initialSceneKey: SceneKey? = null,
+ ) {
+ featureFlags.set(Flags.SCENE_CONTAINER, isFeatureEnabled)
+ authenticationRepository.setUnlocked(isDeviceUnlocked)
+ authenticationRepository.setBypassEnabled(isBypassEnabled)
+ initialSceneKey?.let {
+ sceneInteractor.setCurrentScene(SceneContainerNames.SYSTEM_UI_DEFAULT, SceneModel(it))
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index cd2f5af..6882be7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -40,7 +40,7 @@
private val underTest =
SceneContainerViewModel(
interactor = interactor,
- containerName = "container1",
+ containerName = SceneTestUtils.CONTAINER_1,
)
@Test
@@ -48,10 +48,10 @@
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isTrue()
- interactor.setVisible("container1", false)
+ interactor.setVisible(SceneTestUtils.CONTAINER_1, false)
assertThat(isVisible).isFalse()
- interactor.setVisible("container1", true)
+ interactor.setVisible(SceneTestUtils.CONTAINER_1, true)
assertThat(isVisible).isTrue()
}
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 7646193..5c35913 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
@@ -23,22 +23,28 @@
import android.testing.TestableLooper
import android.view.View
import android.view.ViewGroup
+import android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.android.systemui.settings.FakeDisplayTracker
import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.Executor
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.eq
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@@ -49,9 +55,12 @@
@Mock private lateinit var userTracker: UserTracker
@Mock private lateinit var brightnessSliderControllerFactory: BrightnessSliderController.Factory
- @Mock private lateinit var mainExecutor: Executor
@Mock private lateinit var backgroundHandler: Handler
@Mock private lateinit var brightnessSliderController: BrightnessSliderController
+ @Mock private lateinit var accessibilityMgr: AccessibilityManagerWrapper
+
+ private val clock = FakeSystemClock()
+ private val mainExecutor = FakeExecutor(clock)
private var displayTracker = FakeDisplayTracker(mContext)
@@ -59,19 +68,18 @@
@JvmField
var activityRule =
ActivityTestRule(
- object : SingleActivityFactory<TestDialog>(TestDialog::class.java) {
- override fun create(intent: Intent?): TestDialog {
- return TestDialog(
- userTracker,
- displayTracker,
- brightnessSliderControllerFactory,
- mainExecutor,
- backgroundHandler
- )
- }
+ /* activityFactory= */ SingleActivityFactory {
+ TestDialog(
+ userTracker,
+ displayTracker,
+ brightnessSliderControllerFactory,
+ mainExecutor,
+ backgroundHandler,
+ accessibilityMgr
+ )
},
- false,
- false
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
)
@Before
@@ -80,8 +88,6 @@
`when`(brightnessSliderControllerFactory.create(any(), any()))
.thenReturn(brightnessSliderController)
`when`(brightnessSliderController.rootView).thenReturn(View(context))
-
- activityRule.launchActivity(null)
}
@After
@@ -91,6 +97,7 @@
@Test
fun testGestureExclusion() {
+ activityRule.launchActivity(Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG))
val frame = activityRule.activity.requireViewById<View>(R.id.brightness_mirror_container)
val lp = frame.layoutParams as ViewGroup.MarginLayoutParams
@@ -107,18 +114,83 @@
.isEqualTo(Rect(-horizontalMargin, 0, frame.width + horizontalMargin, frame.height))
}
+ @Test
+ fun testTimeout() {
+ `when`(
+ accessibilityMgr.getRecommendedTimeoutMillis(
+ eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
+ anyInt()
+ )
+ )
+ .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
+ val intent = Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)
+ intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true)
+ activityRule.launchActivity(intent)
+
+ assertThat(activityRule.activity.isFinishing()).isFalse()
+
+ clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong())
+ assertThat(activityRule.activity.isFinishing()).isTrue()
+ }
+
+ @Test
+ fun testRestartTimeout() {
+ `when`(
+ accessibilityMgr.getRecommendedTimeoutMillis(
+ eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
+ anyInt()
+ )
+ )
+ .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
+ val intent = Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG)
+ intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true)
+ activityRule.launchActivity(intent)
+
+ assertThat(activityRule.activity.isFinishing()).isFalse()
+
+ clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong() / 2)
+ // Restart the timeout
+ activityRule.activity.onResume()
+
+ clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong() / 2)
+ // The dialog should not have disappeared yet
+ assertThat(activityRule.activity.isFinishing()).isFalse()
+
+ clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong() / 2)
+ assertThat(activityRule.activity.isFinishing()).isTrue()
+ }
+
+ @Test
+ fun testNoTimeoutIfNotStartedByBrightnessKey() {
+ `when`(
+ accessibilityMgr.getRecommendedTimeoutMillis(
+ eq(BrightnessDialog.DIALOG_TIMEOUT_MILLIS),
+ anyInt()
+ )
+ )
+ .thenReturn(BrightnessDialog.DIALOG_TIMEOUT_MILLIS)
+ activityRule.launchActivity(Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG))
+
+ assertThat(activityRule.activity.isFinishing()).isFalse()
+
+ clock.advanceTime(BrightnessDialog.DIALOG_TIMEOUT_MILLIS.toLong())
+ assertThat(activityRule.activity.isFinishing()).isFalse()
+ }
+
class TestDialog(
userTracker: UserTracker,
displayTracker: FakeDisplayTracker,
brightnessSliderControllerFactory: BrightnessSliderController.Factory,
- mainExecutor: Executor,
- backgroundHandler: Handler
+ mainExecutor: DelayableExecutor,
+ backgroundHandler: Handler,
+ accessibilityMgr: AccessibilityManagerWrapper
) :
BrightnessDialog(
userTracker,
displayTracker,
brightnessSliderControllerFactory,
mainExecutor,
- backgroundHandler
+ backgroundHandler,
+ accessibilityMgr
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
index 729c4a9..52e0c9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeControllerImplTest.kt
@@ -78,11 +78,11 @@
deviceProvisionedController,
notificationShadeWindowController,
windowManager,
+ Lazy { shadeViewController },
Lazy { assistManager },
Lazy { gutsManager },
)
shadeController.setNotificationShadeWindowViewController(nswvc)
- shadeController.setShadeViewController(shadeViewController)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index 3ea8f54..cdcd1a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -20,6 +20,7 @@
import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.content.pm.UserInfo
import android.os.UserManager
import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
@@ -47,6 +48,7 @@
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@@ -92,6 +94,23 @@
mainDispatcher = testDispatcher,
repository = userRepository,
)
+
+ runBlocking {
+ val userInfos =
+ listOf(
+ UserInfo(
+ /* id= */ 0,
+ /* name= */ "zero",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_PRIMARY or
+ UserInfo.FLAG_ADMIN or
+ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ )
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
+ }
userInteractor =
UserInteractor(
applicationContext = context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 5d2d192..6e9fba6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -22,7 +22,6 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.SceneTestUtils.Companion.CONTAINER_1
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
@@ -54,7 +53,6 @@
override fun create(containerName: String): LockscreenSceneInteractor {
return utils.lockScreenSceneInteractor(
authenticationInteractor = authenticationInteractor,
- sceneInteractor = sceneInteractor,
bouncerInteractor =
utils.bouncerInteractor(
authenticationInteractor = authenticationInteractor,
@@ -70,9 +68,7 @@
fun upTransitionSceneKey_deviceLocked_lockScreen() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Lockscreen)
@@ -82,9 +78,7 @@
fun upTransitionSceneKey_deviceUnlocked_gone() =
testScope.runTest {
val upTransitionSceneKey by collectLastValue(underTest.upDestinationSceneKey)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
assertThat(upTransitionSceneKey).isEqualTo(SceneKey.Gone)
@@ -93,10 +87,9 @@
@Test
fun onContentClicked_deviceUnlocked_switchesToGone() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(true)
runCurrent()
@@ -108,10 +101,9 @@
@Test
fun onContentClicked_deviceLockedSecurely_switchesToBouncer() =
testScope.runTest {
- val currentScene by collectLastValue(sceneInteractor.currentScene(CONTAINER_1))
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
+ val currentScene by
+ collectLastValue(sceneInteractor.currentScene(SceneTestUtils.CONTAINER_1))
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
utils.authenticationRepository.setUnlocked(false)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
new file mode 100644
index 0000000..d44846e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerBaseTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
+
+import static com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR;
+import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;
+import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AlarmManager;
+import android.app.Instrumentation;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
+import android.app.trust.TrustManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Looper;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.testing.TestableLooper;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardLogger;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.FaceHelpMessageDeferral;
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
+import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dock.DockManager;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.keyguard.KeyguardIndication;
+import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
+import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
+import com.android.systemui.keyguard.util.IndicationHelper;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
+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.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.util.wakelock.WakeLockFake;
+
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class KeyguardIndicationControllerBaseTest extends SysuiTestCase {
+
+ protected static final String ORGANIZATION_NAME = "organization";
+
+ protected static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName(
+ "com.android.foo",
+ "bar");
+
+ protected static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked;
+
+ protected String mDisclosureWithOrganization;
+ protected String mDisclosureGeneric;
+ protected String mFinancedDisclosureWithOrganization;
+
+ @Mock
+ protected DevicePolicyManager mDevicePolicyManager;
+ @Mock
+ protected DevicePolicyResourcesManager mDevicePolicyResourcesManager;
+ @Mock
+ protected ViewGroup mIndicationArea;
+ @Mock
+ protected KeyguardStateController mKeyguardStateController;
+ @Mock
+ protected KeyguardIndicationTextView mIndicationAreaBottom;
+ @Mock
+ protected BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
+ protected StatusBarStateController mStatusBarStateController;
+ @Mock
+ protected KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock
+ protected UserManager mUserManager;
+ @Mock
+ protected IBatteryStats mIBatteryStats;
+ @Mock
+ protected DockManager mDockManager;
+ @Mock
+ protected KeyguardIndicationRotateTextViewController mRotateTextViewController;
+ @Mock
+ protected FalsingManager mFalsingManager;
+ @Mock
+ protected LockPatternUtils mLockPatternUtils;
+ @Mock
+ protected KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ protected AccessibilityManager mAccessibilityManager;
+ @Mock
+ protected FaceHelpMessageDeferral mFaceHelpMessageDeferral;
+ @Mock
+ protected AlternateBouncerInteractor mAlternateBouncerInteractor;
+ @Mock
+ protected ScreenLifecycle mScreenLifecycle;
+ @Mock
+ protected AuthController mAuthController;
+ @Mock
+ protected AlarmManager mAlarmManager;
+ @Mock
+ protected UserTracker mUserTracker;
+ @Captor
+ protected ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
+ @Captor
+ protected ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
+ @Captor
+ protected ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+ @Captor
+ protected ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
+ @Captor
+ protected ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
+ @Captor
+ protected ArgumentCaptor<KeyguardStateController.Callback>
+ mKeyguardStateControllerCallbackCaptor;
+ @Captor
+ protected ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
+ protected KeyguardStateController.Callback mKeyguardStateControllerCallback;
+ protected KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+ protected StatusBarStateController.StateListener mStatusBarStateListener;
+ protected ScreenLifecycle.Observer mScreenObserver;
+ protected BroadcastReceiver mBroadcastReceiver;
+ protected IndicationHelper mIndicationHelper;
+ protected FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ protected TestableLooper mTestableLooper;
+ protected final int mCurrentUserId = 1;
+
+ protected KeyguardIndicationTextView mTextView; // AOD text
+
+ protected KeyguardIndicationController mController;
+ protected WakeLockFake.Builder mWakeLockBuilder;
+ protected WakeLockFake mWakeLock;
+ protected Instrumentation mInstrumentation;
+ protected FakeFeatureFlags mFlags;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mTestableLooper = TestableLooper.get(this);
+ mTextView = new KeyguardIndicationTextView(mContext);
+ mTextView.setAnimationsEnabled(false);
+
+ // TODO(b/259908270): remove
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
+ DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
+ /* makeDefault= */ false);
+ mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
+ mContext.addMockSystemService(UserManager.class, mUserManager);
+ mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
+ mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
+ mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
+ ORGANIZATION_NAME);
+ mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
+ mFinancedDisclosureWithOrganization = mContext.getString(
+ R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
+
+ when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
+ when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON);
+ when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
+
+ when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
+ .thenReturn(mIndicationAreaBottom);
+ when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
+
+ when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
+ when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
+ .thenReturn(DEVICE_OWNER_COMPONENT);
+ when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false);
+ // TODO(b/259908270): remove
+ when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
+ .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
+
+ when(mDevicePolicyResourcesManager.getString(anyString(), any()))
+ .thenReturn(mDisclosureGeneric);
+ when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
+ .thenReturn(mDisclosureWithOrganization);
+ when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
+
+ mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);
+
+ mWakeLock = new WakeLockFake();
+ mWakeLockBuilder = new WakeLockFake.Builder(mContext);
+ mWakeLockBuilder.setWakeLock(mWakeLock);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTextView.setAnimationsEnabled(true);
+ if (mController != null) {
+ mController.destroy();
+ mController = null;
+ }
+ }
+
+ protected void createController() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mFlags = new FakeFeatureFlags();
+ mFlags.set(KEYGUARD_TALKBACK_FIX, true);
+ mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
+ mFlags.set(FACE_AUTH_REFACTOR, false);
+ mController = new KeyguardIndicationController(
+ mContext,
+ mTestableLooper.getLooper(),
+ mWakeLockBuilder,
+ mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
+ mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
+ mUserManager, mExecutor, mExecutor, mFalsingManager,
+ mAuthController, mLockPatternUtils, mScreenLifecycle,
+ mKeyguardBypassController, mAccessibilityManager,
+ mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
+ mAlternateBouncerInteractor,
+ mAlarmManager,
+ mUserTracker,
+ mock(BouncerMessageInteractor.class),
+ mFlags,
+ mIndicationHelper,
+ KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor()
+ );
+ mController.init();
+ mController.setIndicationArea(mIndicationArea);
+ verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
+ mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
+ verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
+ mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
+ mController.mRotateTextViewController = mRotateTextViewController;
+ mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+ clearInvocations(mIBatteryStats);
+
+ verify(mKeyguardStateController).addCallback(
+ mKeyguardStateControllerCallbackCaptor.capture());
+ mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
+
+ verify(mKeyguardUpdateMonitor).registerCallback(
+ mKeyguardUpdateMonitorCallbackCaptor.capture());
+ mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
+
+ verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
+ mScreenObserver = mScreenObserverCaptor.getValue();
+
+ mExecutor.runAllReady();
+ reset(mRotateTextViewController);
+ }
+}
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 66f8b80..1240f26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -11,12 +11,11 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.systemui.statusbar;
-import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
@@ -26,7 +25,6 @@
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_AVAILABLE;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
-import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
@@ -38,7 +36,6 @@
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRUST;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_OFF;
-import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_TURNING_ON;
import static com.google.common.truth.Truth.assertThat;
@@ -60,74 +57,29 @@
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;
-import android.app.trust.TrustManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.graphics.Color;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.fingerprint.FingerprintManager;
import android.os.BatteryManager;
-import android.os.Looper;
import android.os.RemoteException;
-import android.os.UserManager;
-import android.provider.DeviceConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.TrustGrantFlags;
-import com.android.keyguard.logging.KeyguardLogger;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.biometrics.FaceHelpMessageDeferral;
-import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
-import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardIndication;
import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController;
-import com.android.systemui.keyguard.ScreenLifecycle;
-import com.android.systemui.keyguard.util.IndicationHelper;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-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.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.util.wakelock.WakeLockFake;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import java.text.NumberFormat;
import java.util.Collections;
@@ -138,205 +90,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
-public class KeyguardIndicationControllerTest extends SysuiTestCase {
-
- private static final String ORGANIZATION_NAME = "organization";
-
- private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
- "bar");
-
- private static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked;
-
- private String mDisclosureWithOrganization;
- private String mDisclosureGeneric;
- private String mFinancedDisclosureWithOrganization;
-
- @Mock
- private DevicePolicyManager mDevicePolicyManager;
- @Mock
- private DevicePolicyResourcesManager mDevicePolicyResourcesManager;
- @Mock
- private ViewGroup mIndicationArea;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- private KeyguardIndicationTextView mIndicationAreaBottom;
- @Mock
- private BroadcastDispatcher mBroadcastDispatcher;
- @Mock
- private StatusBarStateController mStatusBarStateController;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- @Mock
- private UserManager mUserManager;
- @Mock
- private IBatteryStats mIBatteryStats;
- @Mock
- private DockManager mDockManager;
- @Mock
- private KeyguardIndicationRotateTextViewController mRotateTextViewController;
- @Mock
- private FalsingManager mFalsingManager;
- @Mock
- private LockPatternUtils mLockPatternUtils;
- @Mock
- private KeyguardBypassController mKeyguardBypassController;
- @Mock
- private AccessibilityManager mAccessibilityManager;
- @Mock
- private FaceHelpMessageDeferral mFaceHelpMessageDeferral;
- @Mock
- private AlternateBouncerInteractor mAlternateBouncerInteractor;
- @Mock
- private ScreenLifecycle mScreenLifecycle;
- @Mock
- private AuthController mAuthController;
- @Mock
- private AlarmManager mAlarmManager;
- @Mock
- private UserTracker mUserTracker;
- @Captor
- private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
- @Captor
- private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
- @Captor
- private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
- @Captor
- private ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor;
- @Captor
- private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor;
- @Captor
- private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor;
- @Captor
- private ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor;
- private KeyguardStateController.Callback mKeyguardStateControllerCallback;
- private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
- private StatusBarStateController.StateListener mStatusBarStateListener;
- private ScreenLifecycle.Observer mScreenObserver;
- private BroadcastReceiver mBroadcastReceiver;
- private IndicationHelper mIndicationHelper;
- private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
- private TestableLooper mTestableLooper;
- private final int mCurrentUserId = 1;
-
- private KeyguardIndicationTextView mTextView; // AOD text
-
- private KeyguardIndicationController mController;
- private WakeLockFake.Builder mWakeLockBuilder;
- private WakeLockFake mWakeLock;
- private Instrumentation mInstrumentation;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mTestableLooper = TestableLooper.get(this);
- mTextView = new KeyguardIndicationTextView(mContext);
- mTextView.setAnimationsEnabled(false);
-
- // TODO(b/259908270): remove
- DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
- DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true",
- /* makeDefault= */ false);
- mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
- mContext.addMockSystemService(UserManager.class, mUserManager);
- mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
- mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
- mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
- ORGANIZATION_NAME);
- mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic);
- mFinancedDisclosureWithOrganization = mContext.getString(
- R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME);
-
- when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
- when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON);
- when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true);
-
- when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom))
- .thenReturn(mIndicationAreaBottom);
- when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
-
- when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager);
- when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser())
- .thenReturn(DEVICE_OWNER_COMPONENT);
- when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false);
- // TODO(b/259908270): remove
- when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
- .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
-
- when(mDevicePolicyResourcesManager.getString(anyString(), any()))
- .thenReturn(mDisclosureGeneric);
- when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString()))
- .thenReturn(mDisclosureWithOrganization);
- when(mUserTracker.getUserId()).thenReturn(mCurrentUserId);
-
- mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor);
-
- mWakeLock = new WakeLockFake();
- mWakeLockBuilder = new WakeLockFake.Builder(mContext);
- mWakeLockBuilder.setWakeLock(mWakeLock);
- }
-
- @After
- public void tearDown() throws Exception {
- mTextView.setAnimationsEnabled(true);
- if (mController != null) {
- mController.destroy();
- mController = null;
- }
- }
-
- private void createController() {
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
- FakeFeatureFlags flags = new FakeFeatureFlags();
- flags.set(KEYGUARD_TALKBACK_FIX, true);
- mController = new KeyguardIndicationController(
- mContext,
- mTestableLooper.getLooper(),
- mWakeLockBuilder,
- mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor,
- mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats,
- mUserManager, mExecutor, mExecutor, mFalsingManager,
- mAuthController, mLockPatternUtils, mScreenLifecycle,
- mKeyguardBypassController, mAccessibilityManager,
- mFaceHelpMessageDeferral, mock(KeyguardLogger.class),
- mAlternateBouncerInteractor,
- mAlarmManager,
- mUserTracker,
- mock(BouncerMessageInteractor.class),
- flags,
- mIndicationHelper
- );
- mController.init();
- mController.setIndicationArea(mIndicationArea);
- verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
- mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
- verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any());
- mBroadcastReceiver = mBroadcastReceiverCaptor.getValue();
- mController.mRotateTextViewController = mRotateTextViewController;
- mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
- clearInvocations(mIBatteryStats);
-
- verify(mKeyguardStateController).addCallback(
- mKeyguardStateControllerCallbackCaptor.capture());
- mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
-
- verify(mKeyguardUpdateMonitor).registerCallback(
- mKeyguardUpdateMonitorCallbackCaptor.capture());
- mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue();
-
- verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
- mScreenObserver = mScreenObserverCaptor.getValue();
-
- mExecutor.runAllReady();
- reset(mRotateTextViewController);
- }
-
+public class KeyguardIndicationControllerTest extends KeyguardIndicationControllerBaseTest {
@Test
public void createController_setIndicationAreaAgain_destroysPreviousRotateTextViewController() {
// GIVEN a controller with a mocked rotate text view controlller
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
new file mode 100644
index 0000000..cdc7520
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class KeyguardIndicationControllerWithCoroutinesTest : KeyguardIndicationControllerBaseTest() {
+ @Test
+ fun testIndicationAreaVisibility_onLockscreenHostedDreamStateChanged() =
+ runBlocking(IMMEDIATE) {
+ // GIVEN starting state for keyguard indication and wallpaper dream enabled
+ createController()
+ mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, true)
+ mController.setVisible(true)
+
+ // THEN indication area is visible
+ verify(mIndicationArea, times(2)).visibility = View.VISIBLE
+
+ // WHEN the device is dreaming with lockscreen hosted dream
+ mController.mIsActiveDreamLockscreenHostedCallback.accept(
+ true /* isActiveDreamLockscreenHosted */
+ )
+ mExecutor.runAllReady()
+
+ // THEN the indication area is hidden
+ verify(mIndicationArea).visibility = View.GONE
+
+ // WHEN the device stops dreaming with lockscreen hosted dream
+ mController.mIsActiveDreamLockscreenHostedCallback.accept(
+ false /* isActiveDreamLockscreenHosted */
+ )
+ mExecutor.runAllReady()
+
+ // THEN indication area is set visible
+ verify(mIndicationArea, times(3)).visibility = View.VISIBLE
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 1b1f4e4..8d016e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -45,6 +45,7 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -65,6 +66,8 @@
@RunWith(AndroidJUnit4.class)
public class StatusBarIconViewTest extends SysuiTestCase {
+ private static final int TEST_STATUS_BAR_HEIGHT = 150;
+
@Rule
public ExpectedException mThrown = ExpectedException.none();
@@ -184,4 +187,218 @@
// no crash, good
}
+
+ @Test
+ public void testUpdateIconScale_constrainedDrawableSizeLessThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // the icon view layout size would be 60x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, dpIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 50x50. When put the drawable into iconView whose
+ // layout size is 60x150, the drawable size would not be constrained and thus keep 50x50
+ setIconDrawableWithSize(/* width= */ 50, /* height= */ 50);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN both the constrained drawable width/height are less than dpIconSize,
+ // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize
+ float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize;
+ assertEquals(scaleToFitDrawingSize, mIconView.getIconScale(), 0.01f);
+ }
+
+ @Test
+ public void testUpdateIconScale_constrainedDrawableHeightLargerThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // the icon view layout size would be 60x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, dpIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 50x100. When put the drawable into iconView whose
+ // layout size is 60x150, the drawable size would not be constrained and thus keep 50x100
+ setIconDrawableWithSize(/* width= */ 50, /* height= */ 100);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN constrained drawable larger side length 100 >= dpIconSize
+ // THEN the icon is scaled down from larger side length 100 to ensure both side
+ // length fit in dpDrawingSize.
+ float scaleToFitDrawingSize = (float) dpDrawingSize / 100;
+ assertEquals(scaleToFitDrawingSize, mIconView.getIconScale(), 0.01f);
+ }
+
+ @Test
+ public void testUpdateIconScale_constrainedDrawableWidthLargerThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // the icon view layout size would be 60x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, dpIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 100x50. When put the drawable into iconView whose
+ // layout size is 60x150, the drawable size would be constrained to 60x30
+ setIconDrawableWithSize(/* width= */ 100, /* height= */ 50);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN constrained drawable larger side length 60 >= dpIconSize
+ // THEN the icon is scaled down from larger side length 60 to ensure both side
+ // length fit in dpDrawingSize.
+ float scaleToFitDrawingSize = (float) dpDrawingSize / 60;
+ assertEquals(scaleToFitDrawingSize, mIconView.getIconScale(), 0.01f);
+ }
+
+ @Test
+ public void testUpdateIconScale_smallerFontAndConstrainedDrawableSizeLessThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // smaller font scaling causes the spIconSize < dpIconSize
+ int spIconSize = 40;
+ // the icon view layout size would be 40x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 50x50. When put the drawable into iconView whose
+ // layout size is 40x150, the drawable size would be constrained to 40x40
+ setIconDrawableWithSize(/* width= */ 50, /* height= */ 50);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN both the constrained drawable width/height are less than dpIconSize,
+ // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize
+ float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize;
+ // THEN the scaled icon should be scaled down further to fit spIconSize
+ float scaleToFitSpIconSize = (float) spIconSize / dpIconSize;
+ assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f);
+ }
+
+ @Test
+ public void testUpdateIconScale_smallerFontAndConstrainedDrawableHeightLargerThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // smaller font scaling causes the spIconSize < dpIconSize
+ int spIconSize = 40;
+ // the icon view layout size would be 40x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 50x100. When put the drawable into iconView whose
+ // layout size is 40x150, the drawable size would be constrained to 40x80
+ setIconDrawableWithSize(/* width= */ 50, /* height= */ 100);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN constrained drawable larger side length 80 >= dpIconSize
+ // THEN the icon is scaled down from larger side length 80 to ensure both side
+ // length fit in dpDrawingSize.
+ float scaleToFitDrawingSize = (float) dpDrawingSize / 80;
+ // THEN the scaled icon should be scaled down further to fit spIconSize
+ float scaleToFitSpIconSize = (float) spIconSize / dpIconSize;
+ assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f);
+ }
+
+ @Test
+ public void testUpdateIconScale_largerFontAndConstrainedDrawableSizeLessThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // larger font scaling causes the spIconSize > dpIconSize
+ int spIconSize = 80;
+ // the icon view layout size would be 80x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 50x50. When put the drawable into iconView whose
+ // layout size is 80x150, the drawable size would not be constrained and thus keep 50x50
+ setIconDrawableWithSize(/* width= */ 50, /* height= */ 50);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN both the constrained drawable width/height are less than dpIconSize,
+ // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize
+ float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize;
+ // THEN the scaled icon should be scaled up to fit spIconSize
+ float scaleToFitSpIconSize = (float) spIconSize / dpIconSize;
+ assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f);
+ }
+
+ @Test
+ public void testUpdateIconScale_largerFontAndConstrainedDrawableHeightLargerThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // larger font scaling causes the spIconSize > dpIconSize
+ int spIconSize = 80;
+ // the icon view layout size would be 80x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 50x100. When put the drawable into iconView whose
+ // layout size is 80x150, the drawable size would not be constrained and thus keep 50x100
+ setIconDrawableWithSize(/* width= */ 50, /* height= */ 100);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN constrained drawable larger side length 100 >= dpIconSize
+ // THEN the icon is scaled down from larger side length 100 to ensure both side
+ // length fit in dpDrawingSize.
+ float scaleToFitDrawingSize = (float) dpDrawingSize / 100;
+ // THEN the scaled icon should be scaled up to fit spIconSize
+ float scaleToFitSpIconSize = (float) spIconSize / dpIconSize;
+ assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f);
+ }
+
+ @Test
+ public void testUpdateIconScale_largerFontAndConstrainedDrawableWidthLargerThanDpIconSize() {
+ int dpIconSize = 60;
+ int dpDrawingSize = 30;
+ // larger font scaling causes the spIconSize > dpIconSize
+ int spIconSize = 80;
+ // the icon view layout size would be 80x150
+ // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT)
+ setUpIconView(dpIconSize, dpDrawingSize, spIconSize);
+ mIconView.setNotification(mock(StatusBarNotification.class));
+ // the raw drawable size is 100x50. When put the drawable into iconView whose
+ // layout size is 80x150, the drawable size would not be constrained and thus keep 80x40
+ setIconDrawableWithSize(/* width= */ 100, /* height= */ 50);
+ mIconView.maybeUpdateIconScaleDimens();
+
+ // WHEN constrained drawable larger side length 80 >= dpIconSize
+ // THEN the icon is scaled down from larger side length 80 to ensure both side
+ // length fit in dpDrawingSize.
+ float scaleToFitDrawingSize = (float) dpDrawingSize / 80;
+ // THEN the scaled icon should be scaled up to fit spIconSize
+ float scaleToFitSpIconSize = (float) spIconSize / dpIconSize;
+ assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize,
+ mIconView.getIconScale(), 0.01f);
+ }
+
+ /**
+ * Setup iconView dimens for testing. The result icon view layout width would
+ * be spIconSize and height would be 150.
+ *
+ * @param dpIconSize corresponding to status_bar_icon_size
+ * @param dpDrawingSize corresponding to status_bar_icon_drawing_size
+ * @param spIconSize corresponding to status_bar_icon_size_sp under different font scaling
+ */
+ private void setUpIconView(int dpIconSize, int dpDrawingSize, int spIconSize) {
+ mIconView.setIncreasedSize(false);
+ mIconView.mOriginalStatusBarIconSize = dpIconSize;
+ mIconView.mStatusBarIconDrawingSize = dpDrawingSize;
+
+ mIconView.mNewStatusBarIconSize = spIconSize;
+ mIconView.mScaleToFitNewIconSize = (float) spIconSize / dpIconSize;
+
+ // the layout width would be spIconSize + 2 * iconPadding, and we assume iconPadding
+ // is 0 here.
+ ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(spIconSize, TEST_STATUS_BAR_HEIGHT);
+ mIconView.setLayoutParams(lp);
+ }
+
+ private void setIconDrawableWithSize(int width, int height) {
+ Bitmap bitmap = Bitmap.createBitmap(
+ width, height, Bitmap.Config.ARGB_8888);
+ Icon icon = Icon.createWithBitmap(bitmap);
+ mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+ icon, 0, 0, "");
+ // Since we only want to verify icon scale logic here, we directly use
+ // {@link StatusBarIconView#setImageDrawable(Drawable)} to set the image drawable
+ // to iconView instead of call {@link StatusBarIconView#set(StatusBarIcon)}. It's to prevent
+ // the icon drawable size being scaled down when internally calling
+ // {@link StatusBarIconView#getIcon(Context,Context,StatusBarIcon)}.
+ mIconView.setImageDrawable(icon.loadDrawable(mContext));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
new file mode 100644
index 0000000..55b6be9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventChipAnimationControllerTest.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.events
+
+import android.content.Context
+import android.graphics.Rect
+import android.util.Pair
+import android.view.Gravity
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
+import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class SystemEventChipAnimationControllerTest : SysuiTestCase() {
+ private lateinit var controller: SystemEventChipAnimationController
+
+ @Mock private lateinit var sbWindowController: StatusBarWindowController
+ @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider
+
+ private var testView = TestView(mContext)
+ private var viewCreator: ViewCreator = { testView }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ // StatusBarWindowController is mocked. The addViewToWindow function needs to be mocked to
+ // ensure that the chip view is added to a parent view
+ whenever(sbWindowController.addViewToWindow(any(), any())).then {
+ val statusbarFake = FrameLayout(mContext)
+ statusbarFake.layout(
+ portraitArea.left,
+ portraitArea.top,
+ portraitArea.right,
+ portraitArea.bottom,
+ )
+ statusbarFake.addView(
+ it.arguments[0] as View,
+ it.arguments[1] as FrameLayout.LayoutParams
+ )
+ }
+
+ whenever(insetsProvider.getStatusBarContentInsetsForCurrentRotation())
+ .thenReturn(Pair(insets, insets))
+ whenever(insetsProvider.getStatusBarContentAreaForCurrentRotation())
+ .thenReturn(portraitArea)
+
+ controller =
+ SystemEventChipAnimationController(
+ context = mContext,
+ statusBarWindowController = sbWindowController,
+ contentInsetsProvider = insetsProvider,
+ featureFlags = FakeFeatureFlags(),
+ )
+ }
+
+ @Test
+ fun prepareChipAnimation_lazyInitializes() {
+ // Until Dagger can do our initialization, make sure that the first chip animation calls
+ // init()
+ assertFalse(controller.initialized)
+ controller.prepareChipAnimation(viewCreator)
+ assertTrue(controller.initialized)
+ }
+
+ @Test
+ fun prepareChipAnimation_positionsChip() {
+ controller.prepareChipAnimation(viewCreator)
+ val chipRect = controller.chipBounds
+
+ // SB area = 10, 0, 990, 100
+ // chip size = 0, 0, 100, 50
+ assertThat(chipRect).isEqualTo(Rect(890, 25, 990, 75))
+ }
+
+ @Test
+ fun prepareChipAnimation_rotation_repositionsChip() {
+ controller.prepareChipAnimation(viewCreator)
+
+ // Chip has been prepared, and is located at (890, 25, 990, 75)
+ // Rotation should put it into its landscape location:
+ // SB area = 10, 0, 1990, 80
+ // chip size = 0, 0, 100, 50
+
+ whenever(insetsProvider.getStatusBarContentAreaForCurrentRotation())
+ .thenReturn(landscapeArea)
+ getInsetsListener().onStatusBarContentInsetsChanged()
+
+ val chipRect = controller.chipBounds
+ assertThat(chipRect).isEqualTo(Rect(1890, 15, 1990, 65))
+ }
+
+ /** regression test for (b/289378932) */
+ @Test
+ fun fullScreenStatusBar_positionsChipAtTop_withTopGravity() {
+ // In the case of a fullscreen status bar window, the content insets area is still correct
+ // (because it uses the dimens), but the window can be full screen. This seems to happen
+ // when launching an app from the ongoing call chip.
+
+ // GIVEN layout the status bar window fullscreen portrait
+ whenever(sbWindowController.addViewToWindow(any(), any())).then {
+ val statusbarFake = FrameLayout(mContext)
+ statusbarFake.layout(
+ fullScreenSb.left,
+ fullScreenSb.top,
+ fullScreenSb.right,
+ fullScreenSb.bottom,
+ )
+
+ val lp = it.arguments[1] as FrameLayout.LayoutParams
+ assertThat(lp.gravity and Gravity.VERTICAL_GRAVITY_MASK).isEqualTo(Gravity.TOP)
+
+ statusbarFake.addView(
+ it.arguments[0] as View,
+ lp,
+ )
+ }
+
+ // GIVEN insets provider gives the correct content area
+ whenever(insetsProvider.getStatusBarContentAreaForCurrentRotation())
+ .thenReturn(portraitArea)
+
+ // WHEN the controller lays out the chip in a fullscreen window
+ controller.prepareChipAnimation(viewCreator)
+
+ // THEN it still aligns the chip to the content area provided by the insets provider
+ val chipRect = controller.chipBounds
+ assertThat(chipRect).isEqualTo(Rect(890, 25, 990, 75))
+ }
+
+ class TestView(context: Context) : View(context), BackgroundAnimatableView {
+ override val view: View
+ get() = this
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ setMeasuredDimension(100, 50)
+ }
+
+ override fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) {
+ setLeftTopRightBottom(l, t, r, b)
+ }
+ }
+
+ private fun getInsetsListener(): StatusBarContentInsetsChangedListener {
+ val callbackCaptor = argumentCaptor<StatusBarContentInsetsChangedListener>()
+ verify(insetsProvider).addCallback(capture(callbackCaptor))
+ return callbackCaptor.value!!
+ }
+
+ companion object {
+ private val portraitArea = Rect(10, 0, 990, 100)
+ private val landscapeArea = Rect(10, 0, 1990, 80)
+ private val fullScreenSb = Rect(10, 0, 990, 2000)
+
+ // 10px insets on both sides
+ private const val insets = 10
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
new file mode 100644
index 0000000..786856b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/events/SystemEventCoordinatorTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.events
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
+import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State.CONNECTED
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.privacy.PrivacyItemController
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.time.FakeSystemClock
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class SystemEventCoordinatorTest : SysuiTestCase() {
+
+ private val fakeSystemClock = FakeSystemClock()
+ private val featureFlags = FakeFeatureFlags()
+ private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val connectedDisplayInteractor = FakeConnectedDisplayInteractor()
+
+ @Mock lateinit var batteryController: BatteryController
+ @Mock lateinit var privacyController: PrivacyItemController
+ @Mock lateinit var scheduler: SystemStatusAnimationScheduler
+
+ private lateinit var systemEventCoordinator: SystemEventCoordinator
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ systemEventCoordinator =
+ SystemEventCoordinator(
+ fakeSystemClock,
+ batteryController,
+ privacyController,
+ context,
+ featureFlags,
+ TestScope(UnconfinedTestDispatcher()),
+ connectedDisplayInteractor
+ )
+ .apply { attachScheduler(scheduler) }
+ }
+
+ @Test
+ fun startObserving_propagatesConnectedDisplayStatusEvents() =
+ testScope.runTest {
+ systemEventCoordinator.startObserving()
+
+ connectedDisplayInteractor.emit(CONNECTED)
+ connectedDisplayInteractor.emit(CONNECTED)
+
+ verify(scheduler, times(2)).onStatusEvent(any<ConnectedDisplayEvent>())
+ }
+
+ @Test
+ fun stopObserving_doesNotPropagateConnectedDisplayStatusEvents() =
+ testScope.runTest {
+ systemEventCoordinator.startObserving()
+
+ connectedDisplayInteractor.emit(CONNECTED)
+
+ verify(scheduler).onStatusEvent(any<ConnectedDisplayEvent>())
+
+ systemEventCoordinator.stopObserving()
+
+ connectedDisplayInteractor.emit(CONNECTED)
+
+ verifyNoMoreInteractions(scheduler)
+ }
+
+ class FakeConnectedDisplayInteractor : ConnectedDisplayInteractor {
+ private val flow = MutableSharedFlow<ConnectedDisplayInteractor.State>()
+ suspend fun emit(value: ConnectedDisplayInteractor.State) = flow.emit(value)
+ override val connectedDisplayState: Flow<ConnectedDisplayInteractor.State>
+ get() = flow
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index 2fbe871..ea70e9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -32,7 +32,6 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -46,11 +45,14 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineScheduler
@@ -62,9 +64,8 @@
import org.mockito.ArgumentMatchers.same
import org.mockito.Mockito.anyString
import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import java.util.function.Consumer
-import kotlin.time.Duration.Companion.seconds
import org.mockito.Mockito.`when` as whenever
@SmallTest
@@ -75,7 +76,6 @@
private val keyguardNotifVisibilityProvider: KeyguardNotificationVisibilityProvider = mock()
private val keyguardRepository = FakeKeyguardRepository()
private val keyguardTransitionRepository = FakeKeyguardTransitionRepository()
- private val notifPipelineFlags: NotifPipelineFlags = mock()
private val notifPipeline: NotifPipeline = mock()
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider = mock()
private val statusBarStateController: StatusBarStateController = mock()
@@ -136,13 +136,8 @@
)
testScheduler.runCurrent()
- // WHEN: The shade is expanded
- whenever(statusBarStateController.isExpanded).thenReturn(true)
- statusBarStateListener.onExpandedChanged(true)
- testScheduler.runCurrent()
-
- // THEN: The notification is still treated as "unseen" and is not filtered out.
- assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isFalse()
+ // THEN: We are no longer listening for shade expansions
+ verify(statusBarStateController, never()).addCallback(any())
}
}
@@ -152,6 +147,10 @@
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(false)
runKeyguardCoordinatorTest {
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
+
// WHEN: A notification is posted
val fakeEntry = NotificationEntryBuilder().build()
collectionListener.onEntryAdded(fakeEntry)
@@ -162,6 +161,9 @@
// WHEN: The keyguard is now showing
keyguardRepository.setKeyguardShowing(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.AOD)
+ )
testScheduler.runCurrent()
// THEN: The notification is recognized as "seen" and is filtered out.
@@ -169,6 +171,9 @@
// WHEN: The keyguard goes away
keyguardRepository.setKeyguardShowing(false)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.AOD, to = KeyguardState.GONE)
+ )
testScheduler.runCurrent()
// THEN: The notification is shown regardless
@@ -182,9 +187,10 @@
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
runKeyguardCoordinatorTest {
- val fakeEntry = NotificationEntryBuilder()
+ val fakeEntry =
+ NotificationEntryBuilder()
.setNotification(Notification.Builder(mContext, "id").setOngoing(true).build())
- .build()
+ .build()
collectionListener.onEntryAdded(fakeEntry)
// WHEN: The keyguard is now showing
@@ -202,11 +208,13 @@
keyguardRepository.setKeyguardShowing(false)
whenever(statusBarStateController.isExpanded).thenReturn(true)
runKeyguardCoordinatorTest {
- val fakeEntry = NotificationEntryBuilder().build().apply {
- row = mock<ExpandableNotificationRow>().apply {
- whenever(isMediaRow).thenReturn(true)
+ val fakeEntry =
+ NotificationEntryBuilder().build().apply {
+ row =
+ mock<ExpandableNotificationRow>().apply {
+ whenever(isMediaRow).thenReturn(true)
+ }
}
- }
collectionListener.onEntryAdded(fakeEntry)
// WHEN: The keyguard is now showing
@@ -299,14 +307,12 @@
runKeyguardCoordinatorTest {
// WHEN: A new notification is posted
val fakeSummary = NotificationEntryBuilder().build()
- val fakeChild = NotificationEntryBuilder()
+ val fakeChild =
+ NotificationEntryBuilder()
.setGroup(context, "group")
.setGroupSummary(context, false)
.build()
- GroupEntryBuilder()
- .setSummary(fakeSummary)
- .addChild(fakeChild)
- .build()
+ GroupEntryBuilder().setSummary(fakeSummary).addChild(fakeChild).build()
collectionListener.onEntryAdded(fakeSummary)
collectionListener.onEntryAdded(fakeChild)
@@ -331,6 +337,10 @@
runKeyguardCoordinatorTest {
val fakeEntry = NotificationEntryBuilder().build()
collectionListener.onEntryAdded(fakeEntry)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
// WHEN: five seconds have passed
testScheduler.advanceTimeBy(5.seconds)
@@ -338,10 +348,16 @@
// WHEN: Keyguard is no longer showing
keyguardRepository.setKeyguardShowing(false)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
testScheduler.runCurrent()
// WHEN: Keyguard is shown again
keyguardRepository.setKeyguardShowing(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.AOD)
+ )
testScheduler.runCurrent()
// THEN: The notification is now recognized as "seen" and is filtered out.
@@ -354,11 +370,17 @@
// GIVEN: Keyguard is showing, unseen notification is present
keyguardRepository.setKeyguardShowing(true)
runKeyguardCoordinatorTest {
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
val fakeEntry = NotificationEntryBuilder().build()
collectionListener.onEntryAdded(fakeEntry)
// WHEN: Keyguard is no longer showing
keyguardRepository.setKeyguardShowing(false)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
// WHEN: Keyguard is shown again
keyguardRepository.setKeyguardShowing(true)
@@ -369,14 +391,212 @@
}
}
+ @Test
+ fun unseenNotificationIsNotMarkedAsSeenIfNotOnKeyguardLongEnough() {
+ // GIVEN: Keyguard is showing, not dozing, unseen notification is present
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardRepository.setIsDozing(false)
+ runKeyguardCoordinatorTest {
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ val firstEntry = NotificationEntryBuilder().setId(1).build()
+ collectionListener.onEntryAdded(firstEntry)
+ testScheduler.runCurrent()
+
+ // WHEN: one second has passed
+ testScheduler.advanceTimeBy(1.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: another unseen notification is posted
+ val secondEntry = NotificationEntryBuilder().setId(2).build()
+ collectionListener.onEntryAdded(secondEntry)
+ testScheduler.runCurrent()
+
+ // WHEN: four more seconds have passed
+ testScheduler.advanceTimeBy(4.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: the keyguard is no longer showing
+ keyguardRepository.setKeyguardShowing(false)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
+ testScheduler.runCurrent()
+
+ // WHEN: Keyguard is shown again
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
+
+ // THEN: The first notification is considered seen and is filtered out.
+ assertThat(unseenFilter.shouldFilterOut(firstEntry, 0L)).isTrue()
+
+ // THEN: The second notification is still considered unseen and is not filtered out
+ assertThat(unseenFilter.shouldFilterOut(secondEntry, 0L)).isFalse()
+ }
+ }
+
+ @Test
+ fun unseenNotificationOnKeyguardNotMarkedAsSeenIfRemovedAfterThreshold() {
+ // GIVEN: Keyguard is showing, not dozing
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardRepository.setIsDozing(false)
+ runKeyguardCoordinatorTest {
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
+
+ // WHEN: a new notification is posted
+ val entry = NotificationEntryBuilder().setId(1).build()
+ collectionListener.onEntryAdded(entry)
+ testScheduler.runCurrent()
+
+ // WHEN: five more seconds have passed
+ testScheduler.advanceTimeBy(5.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: the notification is removed
+ collectionListener.onEntryRemoved(entry, 0)
+ testScheduler.runCurrent()
+
+ // WHEN: the notification is re-posted
+ collectionListener.onEntryAdded(entry)
+ testScheduler.runCurrent()
+
+ // WHEN: one more second has passed
+ testScheduler.advanceTimeBy(1.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: the keyguard is no longer showing
+ keyguardRepository.setKeyguardShowing(false)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
+ testScheduler.runCurrent()
+
+ // WHEN: Keyguard is shown again
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
+
+ // THEN: The notification is considered unseen and is not filtered out.
+ assertThat(unseenFilter.shouldFilterOut(entry, 0L)).isFalse()
+ }
+ }
+
+ @Test
+ fun unseenNotificationOnKeyguardNotMarkedAsSeenIfRemovedBeforeThreshold() {
+ // GIVEN: Keyguard is showing, not dozing
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardRepository.setIsDozing(false)
+ runKeyguardCoordinatorTest {
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
+
+ // WHEN: a new notification is posted
+ val entry = NotificationEntryBuilder().setId(1).build()
+ collectionListener.onEntryAdded(entry)
+ testScheduler.runCurrent()
+
+ // WHEN: one second has passed
+ testScheduler.advanceTimeBy(1.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: the notification is removed
+ collectionListener.onEntryRemoved(entry, 0)
+ testScheduler.runCurrent()
+
+ // WHEN: the notification is re-posted
+ collectionListener.onEntryAdded(entry)
+ testScheduler.runCurrent()
+
+ // WHEN: one more second has passed
+ testScheduler.advanceTimeBy(1.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: the keyguard is no longer showing
+ keyguardRepository.setKeyguardShowing(false)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
+ testScheduler.runCurrent()
+
+ // WHEN: Keyguard is shown again
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
+
+ // THEN: The notification is considered unseen and is not filtered out.
+ assertThat(unseenFilter.shouldFilterOut(entry, 0L)).isFalse()
+ }
+ }
+
+ @Test
+ fun unseenNotificationOnKeyguardNotMarkedAsSeenIfUpdatedBeforeThreshold() {
+ // GIVEN: Keyguard is showing, not dozing
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardRepository.setIsDozing(false)
+ runKeyguardCoordinatorTest {
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
+
+ // WHEN: a new notification is posted
+ val entry = NotificationEntryBuilder().setId(1).build()
+ collectionListener.onEntryAdded(entry)
+ testScheduler.runCurrent()
+
+ // WHEN: one second has passed
+ testScheduler.advanceTimeBy(1.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: the notification is updated
+ collectionListener.onEntryUpdated(entry)
+ testScheduler.runCurrent()
+
+ // WHEN: four more seconds have passed
+ testScheduler.advanceTimeBy(4.seconds)
+ testScheduler.runCurrent()
+
+ // WHEN: the keyguard is no longer showing
+ keyguardRepository.setKeyguardShowing(false)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE)
+ )
+ testScheduler.runCurrent()
+
+ // WHEN: Keyguard is shown again
+ keyguardRepository.setKeyguardShowing(true)
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(from = KeyguardState.GONE, to = KeyguardState.LOCKSCREEN)
+ )
+ testScheduler.runCurrent()
+
+ // THEN: The notification is considered unseen and is not filtered out.
+ assertThat(unseenFilter.shouldFilterOut(entry, 0L)).isFalse()
+ }
+ }
+
private fun runKeyguardCoordinatorTest(
testBlock: suspend KeyguardCoordinatorTestScope.() -> Unit
) {
val testDispatcher = UnconfinedTestDispatcher()
val testScope = TestScope(testDispatcher)
- val fakeSettings = FakeSettings().apply {
- putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
- }
+ val fakeSettings =
+ FakeSettings().apply {
+ putInt(Settings.Secure.LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS, 1)
+ }
val seenNotificationsProvider = SeenNotificationsProviderImpl()
val keyguardCoordinator =
KeyguardCoordinator(
@@ -387,7 +607,6 @@
keyguardRepository,
keyguardTransitionRepository,
mock<KeyguardCoordinatorLogger>(),
- notifPipelineFlags,
testScope.backgroundScope,
sectionHeaderVisibilityProvider,
fakeSettings,
@@ -397,11 +616,12 @@
keyguardCoordinator.attach(notifPipeline)
testScope.runTest(dispatchTimeoutMs = 1.seconds.inWholeMilliseconds) {
KeyguardCoordinatorTestScope(
- keyguardCoordinator,
- testScope,
- seenNotificationsProvider,
- fakeSettings,
- ).testBlock()
+ keyguardCoordinator,
+ testScope,
+ seenNotificationsProvider,
+ fakeSettings,
+ )
+ .testBlock()
}
}
@@ -414,10 +634,9 @@
val testScheduler: TestCoroutineScheduler
get() = scope.testScheduler
- val onStateChangeListener: Consumer<String> =
- withArgCaptor {
- verify(keyguardNotifVisibilityProvider).addOnStateChangedListener(capture())
- }
+ val onStateChangeListener: Consumer<String> = withArgCaptor {
+ verify(keyguardNotifVisibilityProvider).addOnStateChangedListener(capture())
+ }
val unseenFilter: NotifFilter
get() = keyguardCoordinator.unseenNotifFilter
@@ -426,11 +645,11 @@
verify(notifPipeline).addCollectionListener(capture())
}
- val onHeadsUpChangedListener: OnHeadsUpChangedListener get() =
- withArgCaptor { verify(headsUpManager).addListener(capture()) }
+ val onHeadsUpChangedListener: OnHeadsUpChangedListener
+ get() = withArgCaptor { verify(headsUpManager).addListener(capture()) }
- val statusBarStateListener: StatusBarStateController.StateListener get() =
- withArgCaptor { verify(statusBarStateController).addCallback(capture()) }
+ val statusBarStateListener: StatusBarStateController.StateListener
+ get() = withArgCaptor { verify(statusBarStateController).addCallback(capture()) }
var showOnlyUnseenNotifsOnKeyguardSetting: Boolean
get() =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
new file mode 100644
index 0000000..d5612e8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotifLayoutInflaterFactoryTest.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.statusbar.notification.row
+
+import android.content.Context
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.util.AttributeSet
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertNotNull
+import junit.framework.Assert.assertNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+/** Tests for [NotifLayoutInflaterFactory] */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class NotifLayoutInflaterFactoryTest : SysuiTestCase() {
+
+ @Mock private lateinit var attrs: AttributeSet
+
+ @Before
+ fun before() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun onCreateView_notMatchingViews_returnNull() {
+ // GIVEN
+ val layoutInflaterFactory =
+ createNotifLayoutInflaterFactoryImpl(
+ setOf(
+ createReplacementViewFactory("TextView") { context, attrs ->
+ FrameLayout(context)
+ }
+ )
+ )
+
+ // WHEN
+ val createView = layoutInflaterFactory.onCreateView("ImageView", mContext, attrs)
+
+ // THEN
+ assertNull(createView)
+ }
+
+ @Test
+ fun onCreateView_matchingViews_returnReplacementView() {
+ // GIVEN
+ val layoutInflaterFactory =
+ createNotifLayoutInflaterFactoryImpl(
+ setOf(
+ createReplacementViewFactory("TextView") { context, attrs ->
+ FrameLayout(context)
+ }
+ )
+ )
+
+ // WHEN
+ val createView = layoutInflaterFactory.onCreateView("TextView", mContext, attrs)
+
+ // THEN
+ assertNotNull(createView)
+ assertEquals(requireNotNull(createView)::class.java, FrameLayout::class.java)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun onCreateView_multipleFactory_throwIllegalStateException() {
+ // GIVEN
+ val layoutInflaterFactory =
+ createNotifLayoutInflaterFactoryImpl(
+ setOf(
+ createReplacementViewFactory("TextView") { context, attrs ->
+ FrameLayout(context)
+ },
+ createReplacementViewFactory("TextView") { context, attrs ->
+ LinearLayout(context)
+ }
+ )
+ )
+
+ // WHEN
+ layoutInflaterFactory.onCreateView("TextView", mContext, attrs)
+ }
+
+ private fun createNotifLayoutInflaterFactoryImpl(
+ replacementViewFactories: Set<@JvmSuppressWildcards NotifRemoteViewsFactory>
+ ) = NotifLayoutInflaterFactory(DumpManager(), replacementViewFactories)
+
+ private fun createReplacementViewFactory(
+ replacementName: String,
+ createView: (context: Context, attrs: AttributeSet) -> View
+ ) =
+ object : NotifRemoteViewsFactory {
+ override fun instantiate(
+ parent: View?,
+ name: String,
+ context: Context,
+ attrs: AttributeSet
+ ): View? =
+ if (replacementName == name) {
+ createView(context, attrs)
+ } else {
+ null
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index 3face35..f55b0a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -92,6 +92,7 @@
@Mock private ConversationNotificationProcessor mConversationNotificationProcessor;
@Mock private InflatedSmartReplyState mInflatedSmartReplyState;
@Mock private InflatedSmartReplyViewHolder mInflatedSmartReplies;
+ @Mock private NotifLayoutInflaterFactory mNotifLayoutInflaterFactory;
private final SmartReplyStateInflater mSmartReplyStateInflater =
new SmartReplyStateInflater() {
@@ -130,7 +131,8 @@
mConversationNotificationProcessor,
mock(MediaFeatureFlag.class),
mock(Executor.class),
- mSmartReplyStateInflater);
+ mSmartReplyStateInflater,
+ mNotifLayoutInflaterFactory);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index df47071..1a644d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -158,7 +158,8 @@
mock(ConversationNotificationProcessor.class),
mock(MediaFeatureFlag.class),
mock(Executor.class),
- new MockSmartReplyInflater());
+ new MockSmartReplyInflater(),
+ mock(NotifLayoutInflaterFactory.class));
contentBinder.setInflateSynchronously(true);
mBindStage = new RowContentBindStage(contentBinder,
mock(NotifInflationErrorManager.class),
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 88d8dfc..3d35233 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
@@ -447,10 +447,10 @@
mDeviceProvisionedController,
mNotificationShadeWindowController,
mContext.getSystemService(WindowManager.class),
+ () -> mNotificationPanelViewController,
() -> mAssistManager,
() -> mNotificationGutsManager
));
- mShadeController.setShadeViewController(mNotificationPanelViewController);
mShadeController.setNotificationShadeWindowViewController(
mNotificationShadeWindowViewController);
mShadeController.setNotificationPresenter(mNotificationPresenter);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
index b80b825..c282c1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
@@ -21,6 +21,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
@@ -49,7 +51,7 @@
fun calculateWidthFor_oneIcon_widthForOneIcon() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
/* actual= */ 30f)
@@ -59,7 +61,7 @@
fun calculateWidthFor_fourIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
/* actual= */ 60f)
@@ -69,7 +71,7 @@
fun calculateWidthFor_fiveIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
/* actual= */ 60f)
}
@@ -78,7 +80,7 @@
fun calculateIconXTranslations_shortShelfOneIcon_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
val icon = mockStatusBarIcon()
iconContainer.addView(icon)
@@ -99,7 +101,7 @@
fun calculateIconXTranslations_shortShelfFourIcons_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
@@ -128,7 +130,7 @@
fun calculateIconXTranslations_shortShelfFiveIcons_atCorrectXWithOverflowDot() {
iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f)
- iconContainer.setIconSize(10);
+ iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
@@ -154,6 +156,55 @@
}
@Test
+ fun calculateIconXTranslations_givenWidthEnoughForThreeIcons_atCorrectXWithoutOverflowDot() {
+ iconContainer.setActualPaddingStart(0f)
+ iconContainer.setActualPaddingEnd(0f)
+ iconContainer.setActualLayoutWidth(30)
+ iconContainer.setIconSize(10)
+
+ val iconOne = mockStatusBarIcon()
+ val iconTwo = mockStatusBarIcon()
+ val iconThree = mockStatusBarIcon()
+
+ iconContainer.addView(iconOne)
+ iconContainer.addView(iconTwo)
+ iconContainer.addView(iconThree)
+ assertEquals(3, iconContainer.childCount)
+
+ iconContainer.calculateIconXTranslations()
+ assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
+ assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
+ assertEquals(20f, iconContainer.getIconState(iconThree).xTranslation)
+ assertFalse(iconContainer.areIconsOverflowing())
+ }
+
+ @Test
+ fun calculateIconXTranslations_givenWidthNotEnoughForFourIcons_atCorrectXWithOverflowDot() {
+ iconContainer.setActualPaddingStart(0f)
+ iconContainer.setActualPaddingEnd(0f)
+ iconContainer.setActualLayoutWidth(35)
+ iconContainer.setIconSize(10)
+
+ val iconOne = mockStatusBarIcon()
+ val iconTwo = mockStatusBarIcon()
+ val iconThree = mockStatusBarIcon()
+ val iconFour = mockStatusBarIcon()
+
+ iconContainer.addView(iconOne)
+ iconContainer.addView(iconTwo)
+ iconContainer.addView(iconThree)
+ iconContainer.addView(iconFour)
+ assertEquals(4, iconContainer.childCount)
+
+ iconContainer.calculateIconXTranslations()
+ assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
+ assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
+ assertEquals(STATE_DOT, iconContainer.getIconState(iconThree).visibleState)
+ assertEquals(STATE_HIDDEN, iconContainer.getIconState(iconFour).visibleState)
+ assertTrue(iconContainer.areIconsOverflowing())
+ }
+
+ @Test
fun shouldForceOverflow_appearingAboveSpeedBump_true() {
val forceOverflow = iconContainer.shouldForceOverflow(
/* i= */ 1,
@@ -161,7 +212,7 @@
/* iconAppearAmount= */ 1f,
/* maxVisibleIcons= */ 5
)
- assertTrue(forceOverflow);
+ assertTrue(forceOverflow)
}
@Test
@@ -172,7 +223,7 @@
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
)
- assertTrue(forceOverflow);
+ assertTrue(forceOverflow)
}
@Test
@@ -183,7 +234,7 @@
/* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5
)
- assertFalse(forceOverflow);
+ assertFalse(forceOverflow)
}
@Test
@@ -210,6 +261,17 @@
}
@Test
+ fun isOverflowing_lastChildXGreaterThanDotX_true() {
+ val isOverflowing = iconContainer.isOverflowing(
+ /* isLastChild= */ true,
+ /* translationX= */ 9f,
+ /* layoutEnd= */ 10f,
+ /* iconSize= */ 2f,
+ )
+ assertTrue(isOverflowing)
+ }
+
+ @Test
fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() {
val isOverflowing = iconContainer.isOverflowing(
/* isLastChild= */ true,
@@ -253,7 +315,7 @@
assertTrue(isOverflowing)
}
- private fun mockStatusBarIcon() : StatusBarIconView {
+ private fun mockStatusBarIcon(): StatusBarIconView {
val iconView = mock(StatusBarIconView::class.java)
whenever(iconView.width).thenReturn(10)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index ab80158..bbc75c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -44,6 +44,9 @@
import android.animation.Animator;
import android.app.AlarmManager;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
@@ -59,11 +62,11 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ShadeInterpolation;
+import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dock.DockManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
-import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -120,6 +123,7 @@
private int mScrimVisibility;
private boolean mAlwaysOnEnabled;
private TestableLooper mLooper;
+ private Context mContext;
@Mock private AlarmManager mAlarmManager;
@Mock private DozeParameters mDozeParameters;
@Mock private LightBarController mLightBarController;
@@ -133,6 +137,7 @@
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@Mock private CoroutineDispatcher mMainDispatcher;
+ @Mock private TypedArray mMockTypedArray;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
// event-dispatch-on-registration pattern caused some of these unit tests to fail.)
@@ -181,10 +186,11 @@
mNumEnds = 0;
mNumCancels = 0;
}
- };
+ }
private AnimatorListener mAnimatorListener = new AnimatorListener();
+ private int mSurfaceColor = 0x112233;
private void finishAnimationsImmediately() {
// Execute code that will trigger animations.
@@ -213,10 +219,17 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
+ mContext = spy(getContext());
+ when(mContext.obtainStyledAttributes(
+ new int[]{com.android.internal.R.attr.materialColorSurface}))
+ .thenReturn(mMockTypedArray);
- mScrimBehind = spy(new ScrimView(getContext()));
- mScrimInFront = new ScrimView(getContext());
- mNotificationsScrim = new ScrimView(getContext());
+ when(mMockTypedArray.getColorStateList(anyInt()))
+ .thenAnswer((invocation) -> ColorStateList.valueOf(mSurfaceColor));
+
+ mScrimBehind = spy(new ScrimView(mContext));
+ mScrimInFront = new ScrimView(mContext);
+ mNotificationsScrim = new ScrimView(mContext);
mAlwaysOnEnabled = true;
mLooper = TestableLooper.get(this);
DejankUtils.setImmediate(true);
@@ -576,7 +589,7 @@
mScrimController.transitionTo(BOUNCER);
finishAnimationsImmediately();
// Front scrim should be transparent
- // Back scrim should be visible without tint
+ // Back scrim should be visible and tinted to the surface color
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, TRANSPARENT,
@@ -584,9 +597,31 @@
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, false,
+ mScrimBehind, true,
mNotificationsScrim, false
));
+
+ assertScrimTint(mScrimBehind, mSurfaceColor);
+ }
+
+ @Test
+ public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
+ assertEquals(BOUNCER.getBehindTint(), 0x112233);
+ mSurfaceColor = 0x223344;
+ mConfigurationController.notifyThemeChanged();
+ assertEquals(BOUNCER.getBehindTint(), 0x223344);
+ }
+
+ @Test
+ public void onThemeChangeWhileClipQsScrim_bouncerBehindTint_remainsBlack() {
+ mScrimController.setClipsQsScrim(true);
+ mScrimController.transitionTo(BOUNCER);
+ finishAnimationsImmediately();
+
+ assertEquals(BOUNCER.getBehindTint(), Color.BLACK);
+ mSurfaceColor = 0x223344;
+ mConfigurationController.notifyThemeChanged();
+ assertEquals(BOUNCER.getBehindTint(), Color.BLACK);
}
@Test
@@ -618,16 +653,17 @@
finishAnimationsImmediately();
// Front scrim should be transparent
- // Back scrim should be visible without tint
+ // Back scrim should be visible and has a tint of surfaceColor
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, TRANSPARENT,
mScrimBehind, OPAQUE));
assertScrimTinted(Map.of(
mScrimInFront, false,
- mScrimBehind, false,
+ mScrimBehind, true,
mNotificationsScrim, false
));
+ assertScrimTint(mScrimBehind, mSurfaceColor);
}
@Test
@@ -1764,6 +1800,13 @@
assertEquals(message, hasTint, scrim.getTint() != Color.TRANSPARENT);
}
+ private void assertScrimTint(ScrimView scrim, int expectedTint) {
+ String message = "Tint test failed with expected scrim tint: "
+ + Integer.toHexString(expectedTint) + " and actual tint: "
+ + Integer.toHexString(scrim.getTint()) + " for scrim: " + getScrimName(scrim);
+ assertEquals(message, expectedTint, scrim.getTint(), 0.1);
+ }
+
private String getScrimName(ScrimView scrim) {
if (scrim == mScrimInFront) {
return "front";
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 c7143de..ed9cf3f 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
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.service.trust.TrustAgentService;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;
@@ -57,6 +58,8 @@
import com.android.keyguard.KeyguardMessageAreaController;
import com.android.keyguard.KeyguardSecurityModel;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.TrustGrantFlags;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor;
@@ -84,7 +87,6 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.google.common.truth.Truth;
@@ -154,7 +156,7 @@
@Captor
private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
@Captor
- private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
+ private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
@Before
@@ -936,18 +938,24 @@
}
@Test
- public void onDeviceUnlocked_hideAlternateBouncerAndClearMessageArea() {
+ public void onTrustChanged_hideAlternateBouncerAndClearMessageArea() {
+ // GIVEN keyguard update monitor callback is registered
+ verify(mKeyguardUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallback.capture());
+
reset(mKeyguardUpdateMonitor);
reset(mKeyguardMessageAreaController);
- // GIVEN keyguard state controller callback is registered
- verify(mKeyguardStateController).addCallback(mKeyguardStateControllerCallback.capture());
-
// GIVEN alternate bouncer state = not visible
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
- // WHEN the device is unlocked
- mKeyguardStateControllerCallback.getValue().onUnlockedChanged();
+ // WHEN the device is trusted by active unlock
+ mKeyguardUpdateMonitorCallback.getValue().onTrustGrantedForCurrentUser(
+ true,
+ true,
+ new TrustGrantFlags(TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD
+ | TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE),
+ null
+ );
// THEN the false visibility state is propagated to the keyguardUpdateMonitor
verify(mKeyguardUpdateMonitor).setAlternateBouncerShowing(eq(false));
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 862eb00..c8b6f13d 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
@@ -159,6 +159,7 @@
mock(),
mock(),
FakeExecutor(FakeSystemClock()),
+ dispatcher,
testScope.backgroundScope,
mock(),
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
index 30b95ef..5bc98e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositorySwitcherTest.kt
@@ -83,6 +83,7 @@
logger,
tableLogger,
mainExecutor,
+ testDispatcher,
testScope.backgroundScope,
wifiManager,
)
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 5ed3a5c..7007345 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
@@ -76,7 +76,8 @@
private lateinit var executor: Executor
private lateinit var connectivityRepository: ConnectivityRepository
- private val testScope = TestScope(UnconfinedTestDispatcher())
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(dispatcher)
@Before
fun setUp() {
@@ -1301,6 +1302,7 @@
logger,
tableLogger,
executor,
+ dispatcher,
testScope.backgroundScope,
wifiManager,
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
index b30c20d..b04eb01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
@@ -25,8 +25,8 @@
import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
-import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.SingleActivityFactory
import com.google.common.truth.Truth.assertThat
import javax.inject.Inject
@@ -49,19 +49,17 @@
open class UsbPermissionActivityTestable @Inject constructor (
val message: UsbAudioWarningDialogMessage
- )
- : UsbPermissionActivity(UsbAudioWarningDialogMessage())
+ ) : UsbPermissionActivity(UsbAudioWarningDialogMessage())
@Rule
@JvmField
- var activityRule = ActivityTestRule<UsbPermissionActivityTestable>(
- object : SingleActivityFactory<UsbPermissionActivityTestable>(
- UsbPermissionActivityTestable::class.java
- ) {
- override fun create(intent: Intent?): UsbPermissionActivityTestable {
- return UsbPermissionActivityTestable(mMessage)
- }
- }, false, false)
+ var activityRule = ActivityTestRule(
+ /* activityFactory= */ SingleActivityFactory {
+ UsbPermissionActivityTestable(mMessage)
+ },
+ /* initialTouchMode= */ false,
+ /* launchActivity= */ false,
+ )
private val activityIntent = Intent(mContext, UsbPermissionActivityTestable::class.java)
.apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index 89dce61..5b418ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -19,10 +19,12 @@
import android.app.ActivityManager
import android.app.admin.DevicePolicyManager
+import android.content.Context
import android.content.Intent
import android.content.pm.UserInfo
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
+import android.os.Process
import android.os.UserHandle
import android.os.UserManager
import android.provider.Settings
@@ -62,7 +64,9 @@
import junit.framework.Assert.assertNotNull
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -76,6 +80,7 @@
import org.mockito.Mock
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -99,11 +104,15 @@
private lateinit var underTest: UserInteractor
+ private lateinit var spyContext: Context
private lateinit var testScope: TestScope
private lateinit var userRepository: FakeUserRepository
+ private lateinit var keyguardReply: KeyguardInteractorFactory.WithDependencies
private lateinit var keyguardRepository: FakeKeyguardRepository
private lateinit var telephonyRepository: FakeTelephonyRepository
+ private lateinit var testDispatcher: TestDispatcher
private lateinit var featureFlags: FakeFeatureFlags
+ private lateinit var refreshUsersScheduler: RefreshUsersScheduler
@Before
fun setUp() {
@@ -123,58 +132,36 @@
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
set(Flags.FACE_AUTH_REFACTOR, true)
}
- val reply = KeyguardInteractorFactory.create(featureFlags = featureFlags)
- keyguardRepository = reply.repository
+ spyContext = spy(context)
+ keyguardReply = KeyguardInteractorFactory.create(featureFlags = featureFlags)
+ keyguardRepository = keyguardReply.repository
userRepository = FakeUserRepository()
telephonyRepository = FakeTelephonyRepository()
- val testDispatcher = StandardTestDispatcher()
+ testDispatcher = StandardTestDispatcher()
testScope = TestScope(testDispatcher)
- val refreshUsersScheduler =
+ refreshUsersScheduler =
RefreshUsersScheduler(
applicationScope = testScope.backgroundScope,
mainDispatcher = testDispatcher,
repository = userRepository,
)
- underTest =
- UserInteractor(
- applicationContext = context,
- repository = userRepository,
- activityStarter = activityStarter,
- keyguardInteractor = reply.keyguardInteractor,
- manager = manager,
- headlessSystemUserMode = headlessSystemUserMode,
- applicationScope = testScope.backgroundScope,
- telephonyInteractor =
- TelephonyInteractor(
- repository = telephonyRepository,
- ),
- broadcastDispatcher = fakeBroadcastDispatcher,
- keyguardUpdateMonitor = keyguardUpdateMonitor,
- backgroundDispatcher = testDispatcher,
- activityManager = activityManager,
- refreshUsersScheduler = refreshUsersScheduler,
- guestUserInteractor =
- GuestUserInteractor(
- applicationContext = context,
- applicationScope = testScope.backgroundScope,
- mainDispatcher = testDispatcher,
- backgroundDispatcher = testDispatcher,
- manager = manager,
- repository = userRepository,
- deviceProvisionedController = deviceProvisionedController,
- devicePolicyManager = devicePolicyManager,
- refreshUsersScheduler = refreshUsersScheduler,
- uiEventLogger = uiEventLogger,
- resumeSessionReceiver = resumeSessionReceiver,
- resetOrExitSessionReceiver = resetOrExitSessionReceiver,
- ),
- uiEventLogger = uiEventLogger,
- featureFlags = featureFlags,
- )
}
@Test
- fun testKeyguardUpdateMonitor_onKeyguardGoingAway() =
+ fun createUserInteractor_processUser_noSecondaryService() {
+ createUserInteractor()
+ verify(spyContext, never()).startServiceAsUser(any(), any())
+ }
+
+ @Test
+ fun createUserInteractor_nonProcessUser_startsSecondaryService() {
+ createUserInteractor(false /* startAsProcessUser */)
+ verify(spyContext).startServiceAsUser(any(), any())
+ }
+
+ @Test
+ fun testKeyguardUpdateMonitor_onKeyguardGoingAway() {
+ createUserInteractor()
testScope.runTest {
val argumentCaptor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
verify(keyguardUpdateMonitor).registerCallback(argumentCaptor.capture())
@@ -184,9 +171,11 @@
val lastValue = collectLastValue(underTest.dialogDismissRequests)
assertNotNull(lastValue)
}
+ }
@Test
- fun onRecordSelected_user() =
+ fun onRecordSelected_user() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -201,9 +190,11 @@
verify(activityManager).switchUser(userInfos[1].id)
Unit
}
+ }
@Test
- fun onRecordSelected_switchToGuestUser() =
+ fun onRecordSelected_switchToGuestUser() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -217,9 +208,11 @@
verify(activityManager).switchUser(userInfos.last().id)
Unit
}
+ }
@Test
- fun onRecordSelected_switchToRestrictedUser() =
+ fun onRecordSelected_switchToRestrictedUser() {
+ createUserInteractor()
testScope.runTest {
var userInfos = createUserInfos(count = 2, includeGuest = false).toMutableList()
userInfos.add(
@@ -242,9 +235,11 @@
verify(activityManager).switchUser(userInfos.last().id)
Unit
}
+ }
@Test
- fun onRecordSelected_enterGuestMode() =
+ fun onRecordSelected_enterGuestMode() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -262,9 +257,11 @@
verify(manager).createGuest(any())
Unit
}
+ }
@Test
- fun onRecordSelected_action() =
+ fun onRecordSelected_action() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -278,9 +275,11 @@
verify(dialogShower, never()).dismiss()
verify(activityStarter).startActivity(any(), anyBoolean())
}
+ }
@Test
- fun users_switcherEnabled() =
+ fun users_switcherEnabled() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -291,9 +290,11 @@
assertUsers(models = value(), count = 3, includeGuest = true)
}
+ }
@Test
- fun users_switchesToSecondUser() =
+ fun users_switchesToSecondUser() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -305,9 +306,11 @@
assertUsers(models = value(), count = 2, selectedIndex = 1)
}
+ }
@Test
- fun users_switcherNotEnabled() =
+ fun users_switcherNotEnabled() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -317,9 +320,11 @@
val value = collectLastValue(underTest.users)
assertUsers(models = value(), count = 1)
}
+ }
@Test
- fun selectedUser() =
+ fun selectedUser() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -332,9 +337,11 @@
userRepository.setSelectedUserInfo(userInfos[1])
assertUser(value(), id = 1, isSelected = true)
}
+ }
@Test
- fun actions_deviceUnlocked() =
+ fun actions_deviceUnlocked() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
@@ -356,9 +363,11 @@
)
)
}
+ }
@Test
- fun actions_deviceUnlocked_fullScreen() =
+ fun actions_deviceUnlocked_fullScreen() {
+ createUserInteractor()
testScope.runTest {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 2, includeGuest = false)
@@ -379,9 +388,11 @@
)
)
}
+ }
@Test
- fun actions_deviceUnlockedUserNotPrimary_emptyList() =
+ fun actions_deviceUnlockedUserNotPrimary_emptyList() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -392,9 +403,11 @@
assertThat(value()).isEqualTo(emptyList<UserActionModel>())
}
+ }
@Test
- fun actions_deviceUnlockedUserIsGuest_emptyList() =
+ fun actions_deviceUnlockedUserIsGuest_emptyList() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = true)
assertThat(userInfos[1].isGuest).isTrue()
@@ -406,9 +419,11 @@
assertThat(value()).isEqualTo(emptyList<UserActionModel>())
}
+ }
@Test
- fun actions_deviceLockedAddFromLockscreenSet_fullList() =
+ fun actions_deviceLockedAddFromLockscreenSet_fullList() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -432,9 +447,11 @@
)
)
}
+ }
@Test
- fun actions_deviceLockedAddFromLockscreenSet_fullList_fullScreen() =
+ fun actions_deviceLockedAddFromLockscreenSet_fullList_fullScreen() {
+ createUserInteractor()
testScope.runTest {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 2, includeGuest = false)
@@ -459,9 +476,11 @@
)
)
}
+ }
@Test
- fun actions_deviceLocked_onlymanageUserIsShown() =
+ fun actions_deviceLocked_onlymanageUserIsShown() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -472,9 +491,11 @@
assertThat(value()).isEqualTo(listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT))
}
+ }
@Test
- fun executeAction_addUser_dismissesDialogAndStartsActivity() =
+ fun executeAction_addUser_dismissesDialogAndStartsActivity() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -486,9 +507,11 @@
.log(MultiUserActionsEvent.CREATE_USER_FROM_USER_SWITCHER)
underTest.onDialogShown()
}
+ }
@Test
- fun executeAction_addSupervisedUser_dismissesDialogAndStartsActivity() =
+ fun executeAction_addSupervisedUser_dismissesDialogAndStartsActivity() {
+ createUserInteractor()
testScope.runTest {
underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
@@ -500,9 +523,11 @@
.isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER)
assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE)
}
+ }
@Test
- fun executeAction_navigateToManageUsers() =
+ fun executeAction_navigateToManageUsers() {
+ createUserInteractor()
testScope.runTest {
underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
@@ -510,9 +535,11 @@
verify(activityStarter).startActivity(intentCaptor.capture(), eq(true))
assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
}
+ }
@Test
- fun executeAction_guestMode() =
+ fun executeAction_guestMode() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -548,9 +575,11 @@
)
verify(activityManager).switchUser(guestUserInfo.id)
}
+ }
@Test
- fun selectUser_alreadySelectedGuestReSelected_exitGuestDialog() =
+ fun selectUser_alreadySelectedGuestReSelected_exitGuestDialog() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = true)
val guestUserInfo = userInfos[1]
@@ -569,9 +598,11 @@
.isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java)
verify(dialogShower, never()).dismiss()
}
+ }
@Test
- fun selectUser_currentlyGuestNonGuestSelected_exitGuestDialog() =
+ fun selectUser_currentlyGuestNonGuestSelected_exitGuestDialog() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = true)
val guestUserInfo = userInfos[1]
@@ -587,9 +618,11 @@
.isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java)
verify(dialogShower, never()).dismiss()
}
+ }
@Test
- fun selectUser_notCurrentlyGuest_switchesUsers() =
+ fun selectUser_notCurrentlyGuest_switchesUsers() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -603,9 +636,11 @@
verify(activityManager).switchUser(userInfos[1].id)
verify(dialogShower).dismiss()
}
+ }
@Test
- fun telephonyCallStateChanges_refreshesUsers() =
+ fun telephonyCallStateChanges_refreshesUsers() {
+ createUserInteractor()
testScope.runTest {
runCurrent()
@@ -616,9 +651,11 @@
assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
}
+ }
@Test
- fun userSwitchedBroadcast() =
+ fun userSwitchedBroadcast() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -634,7 +671,7 @@
userRepository.setSelectedUserInfo(userInfos[1])
runCurrent()
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
+ spyContext,
Intent(Intent.ACTION_USER_SWITCHED)
.putExtra(Intent.EXTRA_USER_HANDLE, userInfos[1].id),
)
@@ -644,10 +681,13 @@
verify(callback2, atLeastOnce()).onUserStateChanged()
assertThat(userRepository.secondaryUserId).isEqualTo(userInfos[1].id)
assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
+ verify(spyContext).startServiceAsUser(any(), eq(UserHandle.of(userInfos[1].id)))
}
+ }
@Test
- fun userInfoChangedBroadcast() =
+ fun userInfoChangedBroadcast() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -655,7 +695,7 @@
val refreshUsersCallCount = userRepository.refreshUsersCallCount
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
+ spyContext,
Intent(Intent.ACTION_USER_INFO_CHANGED),
)
@@ -663,9 +703,11 @@
assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
}
+ }
@Test
- fun systemUserUnlockedBroadcast_refreshUsers() =
+ fun systemUserUnlockedBroadcast_refreshUsers() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -673,7 +715,7 @@
val refreshUsersCallCount = userRepository.refreshUsersCallCount
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
+ spyContext,
Intent(Intent.ACTION_USER_UNLOCKED)
.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_SYSTEM),
)
@@ -681,9 +723,11 @@
assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
}
+ }
@Test
- fun nonSystemUserUnlockedBroadcast_doNotRefreshUsers() =
+ fun nonSystemUserUnlockedBroadcast_doNotRefreshUsers() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -691,15 +735,17 @@
val refreshUsersCallCount = userRepository.refreshUsersCallCount
fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
- context,
+ spyContext,
Intent(Intent.ACTION_USER_UNLOCKED).putExtra(Intent.EXTRA_USER_HANDLE, 1337),
)
assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount)
}
+ }
@Test
- fun userRecords() =
+ fun userRecords() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = false)
userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
@@ -723,9 +769,11 @@
),
)
}
+ }
@Test
- fun userRecordsFullScreen() =
+ fun userRecordsFullScreen() {
+ createUserInteractor()
testScope.runTest {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
val userInfos = createUserInfos(count = 3, includeGuest = false)
@@ -750,9 +798,11 @@
),
)
}
+ }
@Test
- fun selectedUserRecord() =
+ fun selectedUserRecord() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
@@ -768,9 +818,11 @@
isSwitchToEnabled = true,
)
}
+ }
@Test
- fun users_secondaryUser_guestUserCanBeSwitchedTo() =
+ fun users_secondaryUser_guestUserCanBeSwitchedTo() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -781,9 +833,11 @@
assertThat(res()?.size == 3).isTrue()
assertThat(res()?.find { it.isGuest }).isNotNull()
}
+ }
@Test
- fun users_secondaryUser_noGuestAction() =
+ fun users_secondaryUser_noGuestAction() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -793,9 +847,11 @@
val res = collectLastValue(underTest.actions)
assertThat(res()?.find { it == UserActionModel.ENTER_GUEST_MODE }).isNull()
}
+ }
@Test
- fun users_secondaryUser_noGuestUserRecord() =
+ fun users_secondaryUser_noGuestUserRecord() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = true)
userRepository.setUserInfos(userInfos)
@@ -804,9 +860,11 @@
assertThat(underTest.userRecords.value.find { it.isGuest }).isNull()
}
+ }
@Test
- fun showUserSwitcher_fullScreenDisabled_showsDialogSwitcher() =
+ fun showUserSwitcher_fullScreenDisabled_showsDialogSwitcher() {
+ createUserInteractor()
testScope.runTest {
val expandable = mock<Expandable>()
underTest.showUserSwitcher(expandable)
@@ -820,9 +878,11 @@
underTest.onDialogShown()
assertThat(dialogRequest()).isNull()
}
+ }
@Test
- fun showUserSwitcher_fullScreenEnabled_launchesFullScreenDialog() =
+ fun showUserSwitcher_fullScreenEnabled_launchesFullScreenDialog() {
+ createUserInteractor()
testScope.runTest {
featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, true)
@@ -838,9 +898,11 @@
underTest.onDialogShown()
assertThat(dialogRequest()).isNull()
}
+ }
@Test
- fun users_secondaryUser_managedProfileIsNotIncluded() =
+ fun users_secondaryUser_managedProfileIsNotIncluded() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 3, includeGuest = false).toMutableList()
userInfos.add(
@@ -858,9 +920,11 @@
val res = collectLastValue(underTest.users)
assertThat(res()?.size == 3).isTrue()
}
+ }
@Test
- fun currentUserIsNotPrimaryAndUserSwitcherIsDisabled() =
+ fun currentUserIsNotPrimaryAndUserSwitcherIsDisabled() {
+ createUserInteractor()
testScope.runTest {
val userInfos = createUserInfos(count = 2, includeGuest = false)
userRepository.setUserInfos(userInfos)
@@ -869,9 +933,11 @@
val selectedUser = collectLastValue(underTest.selectedUser)
assertThat(selectedUser()).isNotNull()
}
+ }
@Test
- fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled() =
+ fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled() {
+ createUserInteractor()
testScope.runTest {
keyguardRepository.setKeyguardShowing(true)
whenever(manager.getUserSwitchability(any()))
@@ -891,9 +957,11 @@
.filter { it.info == null }
.forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() }
}
+ }
@Test
- fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled_HeadlessMode() =
+ fun userRecords_isActionAndNoUsersUnlocked_actionIsDisabled_HeadlessMode() {
+ createUserInteractor()
testScope.runTest {
keyguardRepository.setKeyguardShowing(true)
whenever(headlessSystemUserMode.isHeadlessSystemUserMode()).thenReturn(true)
@@ -913,6 +981,7 @@
.filter { it.info == null }
.forEach { action -> assertThat(action.isSwitchToEnabled).isFalse() }
}
+ }
private fun assertUsers(
models: List<UserModel>?,
@@ -1005,6 +1074,53 @@
.isEqualTo(type == UserActionModel.ADD_SUPERVISED_USER)
}
+ private fun createUserInteractor(startAsProcessUser: Boolean = true) {
+ val processUserId = Process.myUserHandle().identifier
+ val startUserId = if (startAsProcessUser) processUserId else (processUserId + 1)
+ runBlocking {
+ val userInfo =
+ createUserInfo(id = startUserId, name = "user_$startUserId", isPrimary = true)
+ userRepository.setUserInfos(listOf(userInfo))
+ userRepository.setSelectedUserInfo(userInfo)
+ }
+ underTest =
+ UserInteractor(
+ applicationContext = spyContext,
+ repository = userRepository,
+ activityStarter = activityStarter,
+ keyguardInteractor = keyguardReply.keyguardInteractor,
+ manager = manager,
+ headlessSystemUserMode = headlessSystemUserMode,
+ applicationScope = testScope.backgroundScope,
+ telephonyInteractor =
+ TelephonyInteractor(
+ repository = telephonyRepository,
+ ),
+ broadcastDispatcher = fakeBroadcastDispatcher,
+ keyguardUpdateMonitor = keyguardUpdateMonitor,
+ backgroundDispatcher = testDispatcher,
+ activityManager = activityManager,
+ refreshUsersScheduler = refreshUsersScheduler,
+ guestUserInteractor =
+ GuestUserInteractor(
+ applicationContext = spyContext,
+ applicationScope = testScope.backgroundScope,
+ mainDispatcher = testDispatcher,
+ backgroundDispatcher = testDispatcher,
+ manager = manager,
+ repository = userRepository,
+ deviceProvisionedController = deviceProvisionedController,
+ devicePolicyManager = devicePolicyManager,
+ refreshUsersScheduler = refreshUsersScheduler,
+ uiEventLogger = uiEventLogger,
+ resumeSessionReceiver = resumeSessionReceiver,
+ resetOrExitSessionReceiver = resetOrExitSessionReceiver,
+ ),
+ uiEventLogger = uiEventLogger,
+ featureFlags = featureFlags,
+ )
+ }
+
private fun createUserInfos(
count: Int,
includeGuest: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
index 9cb26e0..2433e12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/StatusBarUserChipViewModelTest.kt
@@ -50,6 +50,7 @@
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle
@@ -237,6 +238,10 @@
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
set(Flags.FACE_AUTH_REFACTOR, true)
}
+ runBlocking {
+ userRepository.setUserInfos(listOf(USER_0))
+ userRepository.setSelectedUserInfo(USER_0)
+ }
return StatusBarUserChipViewModel(
context = context,
interactor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index e3f9fac..8c88f95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -102,6 +102,20 @@
testScope = TestScope(testDispatcher)
userRepository = FakeUserRepository()
runBlocking {
+ val userInfos =
+ listOf(
+ UserInfo(
+ /* id= */ 0,
+ /* name= */ "zero",
+ /* iconPath= */ "",
+ /* flags= */ UserInfo.FLAG_PRIMARY or
+ UserInfo.FLAG_ADMIN or
+ UserInfo.FLAG_FULL,
+ UserManager.USER_TYPE_FULL_SYSTEM,
+ ),
+ )
+ userRepository.setUserInfos(userInfos)
+ userRepository.setSelectedUserInfo(userInfos[0])
userRepository.setSettings(
UserSwitcherSettingsModel(
isUserSwitcherEnabled = true,
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 a09af00..4839eeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -39,6 +39,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -153,6 +154,7 @@
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.taskview.TaskViewTransitions;
+import com.android.wm.shell.transition.Transitions;
import org.junit.After;
import org.junit.Before;
@@ -282,7 +284,7 @@
@Mock
private ScreenOffAnimationController mScreenOffAnimationController;
@Mock
- private TaskViewTransitions mTaskViewTransitions;
+ Transitions mTransitions;
@Mock
private Optional<OneHandedController> mOneHandedOptional;
@Mock
@@ -294,6 +296,8 @@
@Mock
private Icon mAppBubbleIcon;
+ private TaskViewTransitions mTaskViewTransitions;
+
private TestableBubblePositioner mPositioner;
private BubbleData mBubbleData;
@@ -309,6 +313,12 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ doReturn(true).when(mTransitions).isRegistered();
+ }
+ mTaskViewTransitions = new TaskViewTransitions(mTransitions);
+
mTestableLooper = TestableLooper.get(this);
// For the purposes of this test, just run everything synchronously
@@ -1986,7 +1996,7 @@
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
mBubbleController.registerBubbleStateListener(bubbleStateListener);
- mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), true);
+ mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), 500, 1000);
assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/activity/SingleActivityFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/SingleActivityFactory.kt
new file mode 100644
index 0000000..5a92fb1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/activity/SingleActivityFactory.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.activity
+
+import android.app.Activity
+import android.content.Intent
+import androidx.test.runner.intercepting.SingleActivityFactory
+
+/**
+ * Builds a new [SingleActivityFactory] which delegating any call of [SingleActivityFactory.create]
+ * to the [instantiate] parameter.
+ *
+ * For more details, see [SingleActivityFactory].
+ */
+inline fun <reified T : Activity> SingleActivityFactory(
+ crossinline instantiate: (intent: Intent?) -> T,
+): SingleActivityFactory<T> {
+ return object : SingleActivityFactory<T>(T::class.java) {
+ override fun create(intent: Intent?): T = instantiate(intent)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
index a718f70..bebdd40 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt
@@ -16,40 +16,154 @@
package com.android.systemui.authentication.data.repository
+import com.android.internal.widget.LockPatternUtils
+import com.android.internal.widget.LockPatternView
+import com.android.internal.widget.LockscreenCredential
import com.android.keyguard.KeyguardSecurityModel.SecurityMode
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.authentication.shared.model.AuthenticationResultModel
+import com.android.systemui.authentication.shared.model.AuthenticationThrottlingModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
class FakeAuthenticationRepository(
- private val delegate: AuthenticationRepository,
- private val onSecurityModeChanged: (SecurityMode) -> Unit,
-) : AuthenticationRepository by delegate {
+ private val currentTime: () -> Long,
+) : AuthenticationRepository {
+
+ private val _isBypassEnabled = MutableStateFlow(false)
+ override val isBypassEnabled: StateFlow<Boolean> = _isBypassEnabled
+
+ private val _isAutoConfirmEnabled = MutableStateFlow(false)
+ override val isAutoConfirmEnabled: StateFlow<Boolean> = _isAutoConfirmEnabled.asStateFlow()
private val _isUnlocked = MutableStateFlow(false)
override val isUnlocked: StateFlow<Boolean> = _isUnlocked.asStateFlow()
- private var authenticationMethod: AuthenticationMethodModel = DEFAULT_AUTHENTICATION_METHOD
+ override val hintedPinLength: Int = 6
+
+ private val _isPatternVisible = MutableStateFlow(true)
+ override val isPatternVisible: StateFlow<Boolean> = _isPatternVisible.asStateFlow()
+
+ private val _throttling = MutableStateFlow(AuthenticationThrottlingModel())
+ override val throttling: StateFlow<AuthenticationThrottlingModel> = _throttling.asStateFlow()
+
+ private val _authenticationMethod =
+ MutableStateFlow<AuthenticationMethodModel>(DEFAULT_AUTHENTICATION_METHOD)
+ val authenticationMethod: StateFlow<AuthenticationMethodModel> =
+ _authenticationMethod.asStateFlow()
+
+ private var isLockscreenEnabled = true
+ private var failedAttemptCount = 0
+ private var throttlingEndTimestamp = 0L
+ private var credentialOverride: List<Any>? = null
+ private var securityMode: SecurityMode = DEFAULT_AUTHENTICATION_METHOD.toSecurityMode()
override suspend fun getAuthenticationMethod(): AuthenticationMethodModel {
- return authenticationMethod
+ return authenticationMethod.value
}
fun setAuthenticationMethod(authenticationMethod: AuthenticationMethodModel) {
- this.authenticationMethod = authenticationMethod
- onSecurityModeChanged(authenticationMethod.toSecurityMode())
+ _authenticationMethod.value = authenticationMethod
+ securityMode = authenticationMethod.toSecurityMode()
+ }
+
+ fun overrideCredential(pin: List<Int>) {
+ credentialOverride = pin
+ }
+
+ override suspend fun isLockscreenEnabled(): Boolean {
+ return isLockscreenEnabled
+ }
+
+ override suspend fun reportAuthenticationAttempt(isSuccessful: Boolean) {
+ failedAttemptCount = if (isSuccessful) 0 else failedAttemptCount + 1
+ _isUnlocked.value = isSuccessful
+ }
+
+ override suspend fun getPinLength(): Int {
+ return (credentialOverride ?: listOf(1, 2, 3, 4)).size
+ }
+
+ override fun setBypassEnabled(isBypassEnabled: Boolean) {
+ _isBypassEnabled.value = isBypassEnabled
+ }
+
+ override suspend fun getFailedAuthenticationAttemptCount(): Int {
+ return failedAttemptCount
+ }
+
+ override suspend fun getThrottlingEndTimestamp(): Long {
+ return throttlingEndTimestamp
+ }
+
+ override fun setThrottling(throttlingModel: AuthenticationThrottlingModel) {
+ _throttling.value = throttlingModel
}
fun setUnlocked(isUnlocked: Boolean) {
_isUnlocked.value = isUnlocked
}
- companion object {
- val DEFAULT_AUTHENTICATION_METHOD =
- AuthenticationMethodModel.Pin(listOf(1, 2, 3, 4), autoConfirm = false)
+ fun setAutoConfirmEnabled(isEnabled: Boolean) {
+ _isAutoConfirmEnabled.value = isEnabled
+ }
- fun AuthenticationMethodModel.toSecurityMode(): SecurityMode {
+ fun setLockscreenEnabled(isLockscreenEnabled: Boolean) {
+ this.isLockscreenEnabled = isLockscreenEnabled
+ }
+
+ override suspend fun setThrottleDuration(durationMs: Int) {
+ throttlingEndTimestamp = if (durationMs > 0) currentTime() + durationMs else 0
+ }
+
+ override suspend fun checkCredential(
+ credential: LockscreenCredential
+ ): AuthenticationResultModel {
+ val expectedCredential = credentialOverride ?: getExpectedCredential(securityMode)
+ val isSuccessful =
+ when {
+ credential.type != getCurrentCredentialType(securityMode) -> false
+ credential.type == LockPatternUtils.CREDENTIAL_TYPE_PIN ->
+ credential.isPin && credential.matches(expectedCredential)
+ credential.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ->
+ credential.isPassword && credential.matches(expectedCredential)
+ credential.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN ->
+ credential.isPattern && credential.matches(expectedCredential)
+ else -> error("Unexpected credential type ${credential.type}!")
+ }
+
+ return if (
+ isSuccessful || failedAttemptCount < MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING - 1
+ ) {
+ AuthenticationResultModel(
+ isSuccessful = isSuccessful,
+ throttleDurationMs = 0,
+ )
+ } else {
+ AuthenticationResultModel(
+ isSuccessful = false,
+ throttleDurationMs = THROTTLE_DURATION_MS,
+ )
+ }
+ }
+
+ companion object {
+ val DEFAULT_AUTHENTICATION_METHOD = AuthenticationMethodModel.Pin
+ val PATTERN =
+ listOf(
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 0),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(2, 2),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(1, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 0),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 1),
+ AuthenticationMethodModel.Pattern.PatternCoordinate(0, 2),
+ )
+ const val MAX_FAILED_AUTH_TRIES_BEFORE_THROTTLING = 5
+ const val THROTTLE_DURATION_MS = 30000
+
+ private fun AuthenticationMethodModel.toSecurityMode(): SecurityMode {
return when (this) {
is AuthenticationMethodModel.Pin -> SecurityMode.PIN
is AuthenticationMethodModel.Password -> SecurityMode.Password
@@ -58,5 +172,50 @@
is AuthenticationMethodModel.None -> SecurityMode.None
}
}
+
+ @LockPatternUtils.CredentialType
+ private fun getCurrentCredentialType(
+ securityMode: SecurityMode,
+ ): Int {
+ return when (securityMode) {
+ SecurityMode.PIN,
+ SecurityMode.SimPin,
+ SecurityMode.SimPuk -> LockPatternUtils.CREDENTIAL_TYPE_PIN
+ SecurityMode.Password -> LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
+ SecurityMode.Pattern -> LockPatternUtils.CREDENTIAL_TYPE_PATTERN
+ SecurityMode.None -> LockPatternUtils.CREDENTIAL_TYPE_NONE
+ else -> error("Unsupported SecurityMode $securityMode!")
+ }
+ }
+
+ private fun getExpectedCredential(securityMode: SecurityMode): List<Any> {
+ return when (val credentialType = getCurrentCredentialType(securityMode)) {
+ LockPatternUtils.CREDENTIAL_TYPE_PIN -> listOf(1, 2, 3, 4)
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD -> "password".toList()
+ LockPatternUtils.CREDENTIAL_TYPE_PATTERN -> PATTERN.toCells()
+ else -> error("Unsupported credential type $credentialType!")
+ }
+ }
+
+ private fun LockscreenCredential.matches(expectedCredential: List<Any>): Boolean {
+ @Suppress("UNCHECKED_CAST")
+ return when {
+ isPin ->
+ credential.map { byte -> byte.toInt().toChar() - '0' } == expectedCredential
+ isPassword -> credential.map { byte -> byte.toInt().toChar() } == expectedCredential
+ isPattern ->
+ credential.contentEquals(
+ LockPatternUtils.patternToByteArray(
+ expectedCredential as List<LockPatternView.Cell>
+ )
+ )
+ else -> error("Unsupported credential type $type!")
+ }
+ }
+
+ private fun List<AuthenticationMethodModel.Pattern.PatternCoordinate>.toCells():
+ List<LockPatternView.Cell> {
+ return map { coordinate -> LockPatternView.Cell.of(coordinate.y, coordinate.x) }
+ }
}
}
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 f6cbb07..60a4951 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
@@ -68,6 +68,9 @@
private val _isDreamingWithOverlay = MutableStateFlow(false)
override val isDreamingWithOverlay: Flow<Boolean> = _isDreamingWithOverlay
+ private val _isActiveDreamLockscreenHosted = MutableStateFlow(false)
+ override val isActiveDreamLockscreenHosted: StateFlow<Boolean> = _isActiveDreamLockscreenHosted
+
private val _dozeAmount = MutableStateFlow(0f)
override val linearDozeAmount: Flow<Float> = _dozeAmount
@@ -155,6 +158,10 @@
_isDreamingWithOverlay.value = isDreaming
}
+ override fun setIsActiveDreamLockscreenHosted(isLockscreenHosted: Boolean) {
+ _isActiveDreamLockscreenHosted.value = isLockscreenHosted
+ }
+
fun setDozeAmount(dozeAmount: Float) {
_dozeAmount.value = dozeAmount
}
@@ -187,6 +194,10 @@
_statusBarState.value = state
}
+ fun setKeyguardUnlocked(isUnlocked: Boolean) {
+ _isKeyguardUnlocked.value = isUnlocked
+ }
+
override fun isUdfpsSupported(): Boolean {
return _isUdfpsSupported.value
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 0b6e2a2..d797962 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -16,29 +16,32 @@
package com.android.systemui.scene
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode
+import android.content.pm.UserInfo
import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.AuthenticationRepository
-import com.android.systemui.authentication.data.repository.AuthenticationRepositoryImpl
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
-import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository.Companion.toSecurityMode
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.data.repository.BouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
import com.android.systemui.scene.data.repository.SceneContainerRepository
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.SceneContainerConfig
+import com.android.systemui.scene.shared.model.SceneContainerNames
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.StandardTestDispatcher
-import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.currentTime
/**
* Utilities for creating scene container framework related repositories, interactors, and
@@ -48,22 +51,20 @@
class SceneTestUtils(
test: SysuiTestCase,
) {
- val testDispatcher: TestDispatcher by lazy { StandardTestDispatcher() }
- val testScope: TestScope by lazy { TestScope(testDispatcher) }
- private var securityMode: SecurityMode =
- FakeAuthenticationRepository.DEFAULT_AUTHENTICATION_METHOD.toSecurityMode()
+ val testDispatcher = StandardTestDispatcher()
+ val testScope = TestScope(testDispatcher)
+ val featureFlags = FakeFeatureFlags().apply { set(Flags.SCENE_CONTAINER, true) }
+ private val userRepository: UserRepository by lazy {
+ FakeUserRepository().apply {
+ val users = listOf(UserInfo(/* id= */ 0, "name", /* flags= */ 0))
+ setUserInfos(users)
+ runBlocking { setSelectedUserInfo(users.first()) }
+ }
+ }
+
val authenticationRepository: FakeAuthenticationRepository by lazy {
FakeAuthenticationRepository(
- delegate =
- AuthenticationRepositoryImpl(
- applicationScope = applicationScope(),
- getSecurityMode = { securityMode },
- backgroundDispatcher = testDispatcher,
- userRepository = FakeUserRepository(),
- lockPatternUtils = mock(),
- keyguardRepository = FakeKeyguardRepository(),
- ),
- onSecurityModeChanged = { securityMode = it },
+ currentTime = { testScope.currentTime },
)
}
private val context = test.context
@@ -105,7 +106,7 @@
)
}
- fun authenticationRepository(): AuthenticationRepository {
+ fun authenticationRepository(): FakeAuthenticationRepository {
return authenticationRepository
}
@@ -115,6 +116,9 @@
return AuthenticationInteractor(
applicationScope = applicationScope(),
repository = repository,
+ backgroundDispatcher = testDispatcher,
+ userRepository = userRepository,
+ clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } }
)
}
@@ -128,6 +132,7 @@
repository = BouncerRepository(),
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
+ featureFlags = featureFlags,
containerName = CONTAINER_1,
)
}
@@ -144,13 +149,13 @@
return bouncerInteractor
}
},
+ featureFlags = featureFlags,
containerName = CONTAINER_1,
)
}
fun lockScreenSceneInteractor(
authenticationInteractor: AuthenticationInteractor,
- sceneInteractor: SceneInteractor,
bouncerInteractor: BouncerInteractor,
): LockscreenSceneInteractor {
return LockscreenSceneInteractor(
@@ -162,7 +167,6 @@
return bouncerInteractor
}
},
- sceneInteractor = sceneInteractor,
containerName = CONTAINER_1,
)
}
@@ -172,7 +176,7 @@
}
companion object {
- const val CONTAINER_1 = "container1"
+ const val CONTAINER_1 = SceneContainerNames.SYSTEM_UI_DEFAULT
const val CONTAINER_2 = "container2"
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index ba3d434..1482d07 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -110,7 +110,6 @@
private boolean mAlwaysOnMagnificationEnabled = false;
private final DisplayManagerInternal mDisplayManagerInternal;
- private final MagnificationThumbnailFeatureFlag mMagnificationThumbnailFeatureFlag;
@NonNull private final Supplier<MagnificationThumbnail> mThumbnailSupplier;
/**
@@ -643,13 +642,6 @@
}
}
- void onThumbnailFeatureFlagChanged() {
- synchronized (mLock) {
- destroyThumbnail();
- createThumbnailIfSupported();
- }
- }
-
/**
* Updates the current magnification spec.
*
@@ -810,43 +802,19 @@
addInfoChangedCallback(magnificationInfoChangedCallback);
mScaleProvider = scaleProvider;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
- mMagnificationThumbnailFeatureFlag = new MagnificationThumbnailFeatureFlag();
- mMagnificationThumbnailFeatureFlag.addOnChangedListener(
- backgroundExecutor, this::onMagnificationThumbnailFeatureFlagChanged);
if (thumbnailSupplier != null) {
mThumbnailSupplier = thumbnailSupplier;
} else {
mThumbnailSupplier = () -> {
- if (mMagnificationThumbnailFeatureFlag.isFeatureFlagEnabled()) {
- return new MagnificationThumbnail(
- ctx.getContext(),
- ctx.getContext().getSystemService(WindowManager.class),
- new Handler(ctx.getContext().getMainLooper())
- );
- }
- return null;
+ return new MagnificationThumbnail(
+ ctx.getContext(),
+ ctx.getContext().getSystemService(WindowManager.class),
+ new Handler(ctx.getContext().getMainLooper())
+ );
};
}
}
- private void onMagnificationThumbnailFeatureFlagChanged() {
- synchronized (mLock) {
- for (int i = 0; i < mDisplays.size(); i++) {
- onMagnificationThumbnailFeatureFlagChanged(mDisplays.keyAt(i));
- }
- }
- }
-
- private void onMagnificationThumbnailFeatureFlagChanged(int displayId) {
- synchronized (mLock) {
- final DisplayMagnification display = mDisplays.get(displayId);
- if (display == null) {
- return;
- }
- display.onThumbnailFeatureFlagChanged();
- }
- }
-
/**
* Start tracking the magnification region for services that control magnification and the
* magnification gesture handler.
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index f6948e9..effd873 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -172,14 +172,18 @@
}
@Override
- public void onPerformScaleAction(int displayId, float scale) {
+ public void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
if (getFullScreenMagnificationController().isActivated(displayId)) {
getFullScreenMagnificationController().setScaleAndCenter(displayId, scale,
Float.NaN, Float.NaN, false, MAGNIFICATION_GESTURE_HANDLER_ID);
- getFullScreenMagnificationController().persistScale(displayId);
+ if (updatePersistence) {
+ getFullScreenMagnificationController().persistScale(displayId);
+ }
} else if (getWindowMagnificationMgr().isWindowMagnifierEnabled(displayId)) {
getWindowMagnificationMgr().setScale(displayId, scale);
- getWindowMagnificationMgr().persistScale(displayId);
+ if (updatePersistence) {
+ getWindowMagnificationMgr().persistScale(displayId);
+ }
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnailFeatureFlag.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnailFeatureFlag.java
deleted file mode 100644
index 519f31b..0000000
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationThumbnailFeatureFlag.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.accessibility.magnification;
-
-import android.provider.DeviceConfig;
-
-/**
- * Encapsulates the feature flags for magnification thumbnail. {@see DeviceConfig}
- *
- * @hide
- */
-public class MagnificationThumbnailFeatureFlag extends MagnificationFeatureFlagBase {
-
- private static final String NAMESPACE = DeviceConfig.NAMESPACE_ACCESSIBILITY;
- private static final String FEATURE_NAME_ENABLE_MAGNIFIER_THUMBNAIL =
- "enable_magnifier_thumbnail";
-
- @Override
- String getNamespace() {
- return NAMESPACE;
- }
-
- @Override
- String getFeatureName() {
- return FEATURE_NAME_ENABLE_MAGNIFIER_THUMBNAIL;
- }
-
- @Override
- boolean getDefaultValue() {
- return false;
- }
-}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index d96682c..816f22f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -167,8 +167,9 @@
*
* @param displayId The logical display id.
* @param scale the target scale, or {@link Float#NaN} to leave unchanged
+ * @param updatePersistence whether the scale should be persisted
*/
- void onPerformScaleAction(int displayId, float scale);
+ void onPerformScaleAction(int displayId, float scale, boolean updatePersistence);
/**
* Called when the accessibility action is performed.
@@ -977,14 +978,15 @@
}
@Override
- public void onPerformScaleAction(int displayId, float scale) {
+ public void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
if (mTrace.isA11yTracingEnabledForTypes(
FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK)) {
mTrace.logTrace(TAG + "ConnectionCallback.onPerformScaleAction",
FLAGS_WINDOW_MAGNIFICATION_CONNECTION_CALLBACK,
- "displayId=" + displayId + ";scale=" + scale);
+ "displayId=" + displayId + ";scale=" + scale
+ + ";updatePersistence=" + updatePersistence);
}
- mCallback.onPerformScaleAction(displayId, scale);
+ mCallback.onPerformScaleAction(displayId, scale, updatePersistence);
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 82af382..ad8f5e1 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -20,6 +20,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
import android.app.assist.AssistStructure.WindowNode;
@@ -40,6 +42,7 @@
import android.view.WindowManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.widget.RemoteViews;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
@@ -50,6 +53,8 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
public final class Helper {
@@ -83,6 +88,44 @@
throw new UnsupportedOperationException("contains static members only");
}
+ private static boolean checkRemoteViewUriPermissions(
+ @UserIdInt int userId, @NonNull RemoteViews rView) {
+ final AtomicBoolean permissionsOk = new AtomicBoolean(true);
+
+ rView.visitUris(uri -> {
+ int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri);
+ boolean allowed = uriOwnerId == userId;
+ permissionsOk.set(allowed & permissionsOk.get());
+ });
+
+ return permissionsOk.get();
+ }
+
+ /**
+ * Checks the URI permissions of the remote view,
+ * to see if the current userId is able to access it.
+ *
+ * Returns the RemoteView that is passed if user is able, null otherwise.
+ *
+ * TODO: instead of returning a null remoteview when
+ * the current userId cannot access an URI,
+ * return a new RemoteView with the URI removed.
+ */
+ public static @Nullable RemoteViews sanitizeRemoteView(RemoteViews rView) {
+ if (rView == null) return null;
+
+ int userId = ActivityManager.getCurrentUser();
+
+ boolean ok = checkRemoteViewUriPermissions(userId, rView);
+ if (!ok) {
+ Slog.w(TAG,
+ "sanitizeRemoteView() user: " + userId
+ + " tried accessing resource that does not belong to them");
+ }
+ return (ok ? rView : null);
+ }
+
+
@Nullable
static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
if (set == null) return null;
diff --git a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
index dbeb624..fa414e3 100644
--- a/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/DialogFillUi.java
@@ -53,6 +53,7 @@
import com.android.internal.R;
import com.android.server.autofill.AutofillManagerService;
+import com.android.server.autofill.Helper;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -208,7 +209,8 @@
}
private void setHeader(View decor, FillResponse response) {
- final RemoteViews presentation = response.getDialogHeader();
+ final RemoteViews presentation =
+ Helper.sanitizeRemoteView(response.getDialogHeader());
if (presentation == null) {
return;
}
@@ -243,9 +245,10 @@
}
private void initialAuthenticationLayout(View decor, FillResponse response) {
- RemoteViews presentation = response.getDialogPresentation();
+ RemoteViews presentation = Helper.sanitizeRemoteView(
+ response.getDialogPresentation());
if (presentation == null) {
- presentation = response.getPresentation();
+ presentation = Helper.sanitizeRemoteView(response.getPresentation());
}
if (presentation == null) {
throw new RuntimeException("No presentation for fill dialog authentication");
@@ -289,7 +292,8 @@
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
if (index >= 0) {
- RemoteViews presentation = dataset.getFieldDialogPresentation(index);
+ RemoteViews presentation = Helper.sanitizeRemoteView(
+ dataset.getFieldDialogPresentation(index));
if (presentation == null) {
if (sDebug) {
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 129ce72..cdfe7bb 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -148,8 +148,9 @@
final LayoutInflater inflater = LayoutInflater.from(mContext);
- final RemoteViews headerPresentation = response.getHeader();
- final RemoteViews footerPresentation = response.getFooter();
+ final RemoteViews headerPresentation = Helper.sanitizeRemoteView(response.getHeader());
+ final RemoteViews footerPresentation = Helper.sanitizeRemoteView(response.getFooter());
+
final ViewGroup decor;
if (mFullScreen) {
decor = (ViewGroup) inflater.inflate(R.layout.autofill_dataset_picker_fullscreen, null);
@@ -227,6 +228,9 @@
ViewGroup container = decor.findViewById(R.id.autofill_dataset_picker);
final View content;
try {
+ if (Helper.sanitizeRemoteView(response.getPresentation()) == null) {
+ throw new RuntimeException("Permission error accessing RemoteView");
+ }
content = response.getPresentation().applyWithTheme(
mContext, decor, interceptionHandler, mThemeId);
container.addView(content);
@@ -306,7 +310,8 @@
final Dataset dataset = response.getDatasets().get(i);
final int index = dataset.getFieldIds().indexOf(focusedViewId);
if (index >= 0) {
- final RemoteViews presentation = dataset.getFieldPresentation(index);
+ final RemoteViews presentation = Helper.sanitizeRemoteView(
+ dataset.getFieldPresentation(index));
if (presentation == null) {
Slog.w(TAG, "not displaying UI on field " + focusedViewId + " because "
+ "service didn't provide a presentation for it on " + dataset);
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index f035d07..70382f1 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -384,8 +384,7 @@
return false;
}
writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_DESCRIPTION);
-
- final RemoteViews template = customDescription.getPresentation();
+ final RemoteViews template = Helper.sanitizeRemoteView(customDescription.getPresentation());
if (template == null) {
Slog.w(TAG, "No remote view on custom description");
return false;
diff --git a/services/companion/java/com/android/server/companion/virtual/OWNERS b/services/companion/java/com/android/server/companion/virtual/OWNERS
index 5e8291f..83143a4 100644
--- a/services/companion/java/com/android/server/companion/virtual/OWNERS
+++ b/services/companion/java/com/android/server/companion/virtual/OWNERS
@@ -2,4 +2,5 @@
ogunwale@google.com
michaelwr@google.com
-vladokom@google.com
\ No newline at end of file
+vladokom@google.com
+marvinramin@google.com
\ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 9355741..51acfd3 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -1053,8 +1053,8 @@
}
void onEnteringPipBlocked(int uid) {
- showToastWhereUidIsRunning(uid, com.android.internal.R.string.vdm_pip_blocked,
- Toast.LENGTH_LONG, mContext.getMainLooper());
+ // Do nothing. ActivityRecord#checkEnterPictureInPictureState logs that the display does not
+ // support PiP.
}
void playSoundEffect(int effectType) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 63f8ae0..459e24d 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -230,8 +230,7 @@
name: "services.core.json.gz",
srcs: [":checked-protolog.json"],
out: ["services.core.protolog.json.gz"],
- cmd: "$(location minigzip) -c < $(in) > $(out)",
- tools: ["minigzip"],
+ cmd: "gzip -c < $(in) > $(out)",
}
prebuilt_etc {
diff --git a/services/core/java/com/android/server/PendingIntentUtils.java b/services/core/java/com/android/server/PendingIntentUtils.java
index 1600101..a72a4d25 100644
--- a/services/core/java/com/android/server/PendingIntentUtils.java
+++ b/services/core/java/com/android/server/PendingIntentUtils.java
@@ -34,6 +34,7 @@
public static Bundle createDontSendToRestrictedAppsBundle(@Nullable Bundle bundle) {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDontSendToRestrictedApps(true);
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
if (bundle == null) {
return options.toBundle();
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 73dbb86a..ecc0aa5 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2069,7 +2069,7 @@
}
};
// TODO(b/149391976): Use different handler?
- monitor.register(mContext, user, true, mHandler);
+ monitor.register(mContext, user, mHandler);
mPackageMonitorsForUser.put(userId, monitor);
} else {
Slog.w(TAG, "PackageMonitor is already registered for: " + userId);
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 7fae31c..bca2d60 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -1827,6 +1827,9 @@
soname, soname, new String[0], true);
mSharedLibraries.put(entry.name, entry);
}
+ } catch (FileNotFoundException e) {
+ // Expected for /vendor/etc/public.libraries.txt on some devices
+ Slog.d(TAG, listFile + " does not exist");
} catch (IOException e) {
Slog.w(TAG, "Failed to read public libraries file " + listFile, e);
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index ae12258..6baae4b 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -453,7 +453,7 @@
mInterestingJavaPids.add(Process.myPid());
// See the notes on DEFAULT_TIMEOUT.
- assert DB ||
+ assert DB || Build.IS_USERDEBUG ||
DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
mTraceErrorLogger = new TraceErrorLogger();
@@ -527,7 +527,8 @@
*/
void updateWatchdogTimeout(long timeoutMillis) {
// See the notes on DEFAULT_TIMEOUT.
- if (!DB && timeoutMillis <= ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS) {
+ if (!DB && !Build.IS_USERDEBUG
+ && timeoutMillis <= ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS) {
timeoutMillis = ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS + 1;
}
mWatchdogTimeoutMillis = timeoutMillis;
@@ -915,7 +916,7 @@
// The system's been hanging for a whlie, another second or two won't hurt much.
SystemClock.sleep(5000);
processCpuTracker.update();
- report.append(processCpuTracker.printCurrentState(anrTime));
+ report.append(processCpuTracker.printCurrentState(anrTime, 10));
report.append(tracesFileException.getBuffer());
if (!halfWatchdog) {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 9474fc1..f4c8a57 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -417,7 +417,7 @@
}
if (accounts == null) {
- accounts = getAccountsAsUser(null, userId, "android");
+ accounts = getAccountsOrEmptyArray(null, userId, "android");
if (ArrayUtils.isEmpty(accounts)) {
return;
}
@@ -446,7 +446,7 @@
private void cancelAccountAccessRequestNotificationIfNeeded(int uid,
boolean checkAccess, UserAccounts userAccounts) {
- Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
+ Account[] accounts = getAccountsOrEmptyArray(null, UserHandle.getUserId(uid), "android");
for (Account account : accounts) {
cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess, userAccounts);
}
@@ -454,7 +454,7 @@
private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid,
boolean checkAccess, UserAccounts userAccounts) {
- Account[] accounts = getAccountsAsUser(null, UserHandle.getUserId(uid), "android");
+ Account[] accounts = getAccountsOrEmptyArray(null, UserHandle.getUserId(uid), "android");
for (Account account : accounts) {
cancelAccountAccessRequestNotificationIfNeeded(account,
uid, packageName, checkAccess, userAccounts);
@@ -4481,6 +4481,16 @@
}
@NonNull
+ private Account[] getAccountsOrEmptyArray(String type, int userId, String opPackageName) {
+ try {
+ return getAccountsAsUser(type, userId, opPackageName);
+ } catch (SQLiteCantOpenDatabaseException e) {
+ Log.w(TAG, "Could not get accounts for user " + userId, e);
+ return new Account[]{};
+ }
+ }
+
+ @NonNull
private Account[] getAccountsAsUserForPackage(
String type,
int userId,
@@ -4569,7 +4579,7 @@
public void addSharedAccountsFromParentUser(int parentUserId, int userId,
String opPackageName) {
checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser");
- Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName);
+ Account[] accounts = getAccountsOrEmptyArray(null, parentUserId, opPackageName);
for (Account account : accounts) {
addSharedAccountAsUser(account, userId);
}
@@ -5001,7 +5011,10 @@
p.setDataPosition(0);
Bundle simulateBundle = p.readBundle();
p.recycle();
- Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ if (intent != null && intent.getClass() != Intent.class) {
+ return false;
+ }
Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT,
Intent.class);
if (intent == null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 359c3cd..eaa1b97 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8658,7 +8658,7 @@
// cleaning up the old proxies.
VMRuntime.getRuntime().requestConcurrentGC();
}
- }, mHandler);
+ }, BackgroundThread.getHandler());
t.traceEnd(); // setBinderProxies
t.traceEnd(); // ActivityManagerStartApps
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 0fcec6f..fc8175b 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -1144,9 +1144,6 @@
} else if (mProcessPersistent) {
mRunnableAt = runnableAt + constants.DELAY_PERSISTENT_PROC_MILLIS;
mRunnableAtReason = REASON_PERSISTENT;
- } else if (UserHandle.isCore(uid)) {
- mRunnableAt = runnableAt;
- mRunnableAtReason = REASON_CORE_UID;
} else if (mCountOrdered > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_ORDERED;
@@ -1193,6 +1190,9 @@
// is already cached, they'll be deferred on the line above
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_RESULT_TO;
+ } else if (UserHandle.isCore(uid)) {
+ mRunnableAt = runnableAt;
+ mRunnableAtReason = REASON_CORE_UID;
} else {
mRunnableAt = runnableAt + constants.DELAY_NORMAL_MILLIS;
mRunnableAtReason = REASON_NORMAL;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 7e9283a..cc9628f 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -241,7 +241,8 @@
private static final int FREEZE_BINDER_TIMEOUT_MS = 100;
private static final int FREEZE_DEADLOCK_TIMEOUT_MS = 1000;
- @VisibleForTesting static final boolean ENABLE_FILE_COMPACT = false;
+ // If enabled, any compaction issued will apply to code mappings and share memory mappings.
+ @VisibleForTesting static final boolean ENABLE_SHARED_AND_CODE_COMPACT = false;
// Defaults for phenotype flags.
@VisibleForTesting static final boolean DEFAULT_USE_COMPACTION = true;
@@ -1686,7 +1687,7 @@
}
}
- if (!ENABLE_FILE_COMPACT) {
+ if (!ENABLE_SHARED_AND_CODE_COMPACT) {
if (profile == CompactProfile.SOME) {
profile = CompactProfile.NONE;
} else if (profile == CompactProfile.FULL) {
diff --git a/services/core/java/com/android/server/am/ComponentAliasResolver.java b/services/core/java/com/android/server/am/ComponentAliasResolver.java
index f9eaf02..6e93ce4 100644
--- a/services/core/java/com/android/server/am/ComponentAliasResolver.java
+++ b/services/core/java/com/android/server/am/ComponentAliasResolver.java
@@ -162,7 +162,7 @@
// avoid deadlocks.
if (enabled) {
mPackageMonitor.register(mAm.mContext, UserHandle.ALL,
- /* externalStorage= */ false, BackgroundThread.getHandler());
+ BackgroundThread.getHandler());
} else {
mPackageMonitor.unregister();
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 3ab40d2..e26ee9c 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -96,7 +96,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/**
@@ -116,6 +118,8 @@
private final ProviderMap mProviderMap;
private boolean mSystemProvidersInstalled;
+ private final Map<String, Boolean> mCloneProfileAuthorityRedirectionCache = new HashMap<>();
+
ContentProviderHelper(ActivityManagerService service, boolean createProviderMap) {
mService = service;
mProviderMap = createProviderMap ? new ProviderMap(mService) : null;
@@ -201,9 +205,24 @@
final UserProperties userProps = umInternal.getUserProperties(userId);
final boolean isMediaSharedWithParent =
userProps != null && userProps.isMediaSharedWithParent();
- if (!isAuthorityRedirectedForCloneProfile(name) || !isMediaSharedWithParent) {
+ if (!isAuthorityRedirectedForCloneProfileCached(name) || !isMediaSharedWithParent) {
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
+ // In case we are on media authority and callingUid is cloned app asking to access
+ // the contentProvider of user 0 by specifying content as
+ // content://<parent-id>@media/external/file, we skip checkUser.
+ if (isAuthorityRedirectedForCloneProfileCached(name)) {
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ final UserProperties userPropsCallingUser =
+ umInternal.getUserProperties(callingUserId);
+ final boolean isMediaSharedWithParentForCallingUser =
+ userPropsCallingUser != null
+ && userPropsCallingUser.isMediaSharedWithParent();
+ if (isMediaSharedWithParentForCallingUser
+ && umInternal.getProfileParentId(callingUserId) == userId) {
+ checkCrossUser = false;
+ }
+ }
}
// If that didn't work, check if it exists for user 0 and then
// verify that it's a singleton provider before using it.
@@ -218,7 +237,7 @@
r == null ? callingUid : r.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
- } else if (isAuthorityRedirectedForCloneProfile(name)) {
+ } else if (isAuthorityRedirectedForCloneProfileCached(name)) {
if (isMediaSharedWithParent) {
userId = umInternal.getProfileParentId(userId);
checkCrossUser = false;
@@ -1073,7 +1092,7 @@
return false;
}
- if (isAuthorityRedirectedForCloneProfile(holder.info.authority)
+ if (isAuthorityRedirectedForCloneProfileCached(holder.info.authority)
&& resolveParentUserIdForCloneProfile(userId) != userId) {
// Since clone profile shares certain providers with its parent and the access is
// re-directed as well, the holder may not actually be installed on the clone profile.
@@ -1108,7 +1127,7 @@
userId = UserHandle.getCallingUserId();
}
- if (isAuthorityRedirectedForCloneProfile(authority)) {
+ if (isAuthorityRedirectedForCloneProfileCached(authority)) {
UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
UserInfo userInfo = umInternal.getUserInfo(userId);
@@ -1954,4 +1973,14 @@
String[] args) {
return mProviderMap.dumpProviderProto(fd, pw, name, args);
}
+
+ private Boolean isAuthorityRedirectedForCloneProfileCached(String auth) {
+ if (mCloneProfileAuthorityRedirectionCache.containsKey(auth)) {
+ return mCloneProfileAuthorityRedirectionCache.get(auth);
+ } else {
+ boolean isAuthRedirected = isAuthorityRedirectedForCloneProfile(auth);
+ mCloneProfileAuthorityRedirectionCache.put(auth, isAuthRedirected);
+ return isAuthRedirected;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c5776d8..acd9771 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1827,6 +1827,7 @@
if (debuggableFlag) {
runtimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
+ runtimeFlags |= Zygote.DEBUG_ENABLE_PTRACE;
runtimeFlags |= Zygote.DEBUG_JAVA_DEBUGGABLE;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 0b04159..f8f0088 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -613,16 +613,26 @@
@Override
public boolean isCameraDisabled(int userId) {
- DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
- if (dpm == null) {
- Slog.e(TAG, "Failed to get the device policy manager service");
+ if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
+ Slog.e(TAG, "Calling UID: " + Binder.getCallingUid()
+ + " doesn't match expected camera service UID!");
return false;
}
+ final long ident = Binder.clearCallingIdentity();
try {
- return dpm.getCameraDisabled(null, userId);
- } catch (Exception e) {
- e.printStackTrace();
- return false;
+ DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
+ if (dpm == null) {
+ Slog.e(TAG, "Failed to get the device policy manager service");
+ return false;
+ }
+ try {
+ return dpm.getCameraDisabled(null, userId);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
};
diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
index f84a58c..472c1f5 100644
--- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
+++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
@@ -22,7 +22,6 @@
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.Display;
import android.view.DisplayAddress;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,6 +37,7 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.math.BigInteger;
import javax.xml.datatype.DatatypeConfigurationException;
@@ -115,13 +115,16 @@
Slog.i(TAG, "Display layout config not found: " + configFile);
return;
}
- int leadDisplayId = Display.DEFAULT_DISPLAY;
for (com.android.server.display.config.layout.Layout l : layouts.getLayout()) {
final int state = l.getState().intValue();
final Layout layout = createLayout(state);
for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
assert layout != null;
int position = getPosition(d.getPosition());
+ BigInteger leadDisplayPhysicalId = d.getLeadDisplayAddress();
+ DisplayAddress leadDisplayAddress = leadDisplayPhysicalId == null ? null
+ : DisplayAddress.fromPhysicalDisplayId(
+ leadDisplayPhysicalId.longValue());
layout.createDisplayLocked(
DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
d.isDefaultDisplay(),
@@ -129,11 +132,12 @@
d.getDisplayGroup(),
mIdProducer,
position,
- leadDisplayId,
+ leadDisplayAddress,
d.getBrightnessThrottlingMapId(),
d.getRefreshRateZoneId(),
d.getRefreshRateThermalThrottlingMapId());
}
+ layout.postProcessLocked();
}
} catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
Slog.e(TAG, "Encountered an error while reading/parsing display layout config file: "
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index b55d7d5..d9ec3de 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -22,6 +22,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.DisplayAddress;
@@ -77,7 +79,7 @@
DisplayIdProducer idProducer) {
createDisplayLocked(address, /* isDefault= */ true, /* isEnabled= */ true,
DEFAULT_DISPLAY_GROUP_NAME, idProducer, POSITION_UNKNOWN,
- NO_LEAD_DISPLAY, /* brightnessThrottlingMapId= */ null,
+ /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ null,
/* refreshRateZoneId= */ null, /* refreshRateThermalThrottlingMapId= */ null);
}
@@ -90,19 +92,20 @@
* @param displayGroupName Name of the display group to which the display is assigned.
* @param idProducer Produces the logical display id.
* @param position Indicates the position this display is facing in this layout.
- * @param leadDisplayId Display that this one follows (-1 if none).
+ * @param leadDisplayAddress Address of a display that this one follows ({@code null} if none).
* @param brightnessThrottlingMapId Name of which brightness throttling policy should be used.
* @param refreshRateZoneId Layout limited refresh rate zone name.
* @param refreshRateThermalThrottlingMapId Name of which refresh rate throttling
* policy should be used.
-
+ *
* @exception IllegalArgumentException When a default display owns a display group other than
* DEFAULT_DISPLAY_GROUP.
*/
public void createDisplayLocked(
@NonNull DisplayAddress address, boolean isDefault, boolean isEnabled,
- String displayGroupName, DisplayIdProducer idProducer, int position, int leadDisplayId,
- String brightnessThrottlingMapId, @Nullable String refreshRateZoneId,
+ String displayGroupName, DisplayIdProducer idProducer, int position,
+ @Nullable DisplayAddress leadDisplayAddress, String brightnessThrottlingMapId,
+ @Nullable String refreshRateZoneId,
@Nullable String refreshRateThermalThrottlingMapId) {
if (contains(address)) {
Slog.w(TAG, "Attempting to add second definition for display-device: " + address);
@@ -115,21 +118,27 @@
return;
}
- // Assign a logical display ID and create the new display.
- // Note that the logical display ID is saved into the layout, so when switching between
- // different layouts, a logical display can be destroyed and later recreated with the
- // same logical display ID.
if (displayGroupName == null) {
displayGroupName = DEFAULT_DISPLAY_GROUP_NAME;
}
if (isDefault && !displayGroupName.equals(DEFAULT_DISPLAY_GROUP_NAME)) {
throw new IllegalArgumentException("Default display should own DEFAULT_DISPLAY_GROUP");
}
+ if (isDefault && leadDisplayAddress != null) {
+ throw new IllegalArgumentException("Default display cannot have a lead display");
+ }
+ if (address.equals(leadDisplayAddress)) {
+ throw new IllegalArgumentException("Lead display address cannot be the same as display "
+ + " address");
+ }
+ // Assign a logical display ID and create the new display.
+ // Note that the logical display ID is saved into the layout, so when switching between
+ // different layouts, a logical display can be destroyed and later recreated with the
+ // same logical display ID.
final int logicalDisplayId = idProducer.getId(isDefault);
- leadDisplayId = isDefault ? NO_LEAD_DISPLAY : leadDisplayId;
final Display display = new Display(address, logicalDisplayId, isEnabled, displayGroupName,
- brightnessThrottlingMapId, position, leadDisplayId, refreshRateZoneId,
+ brightnessThrottlingMapId, position, leadDisplayAddress, refreshRateZoneId,
refreshRateThermalThrottlingMapId);
mDisplays.add(display);
@@ -146,6 +155,43 @@
}
/**
+ * Applies post-processing to displays to make sure the information of each display is
+ * up-to-date.
+ *
+ * <p>At creation of a display, lead display is specified by display address. At post
+ * processing, we convert it to logical display ID.
+ */
+ public void postProcessLocked() {
+ for (int i = 0; i < mDisplays.size(); i++) {
+ Display display = mDisplays.get(i);
+ if (display.getLogicalDisplayId() == DEFAULT_DISPLAY) {
+ display.setLeadDisplayId(NO_LEAD_DISPLAY);
+ continue;
+ }
+ DisplayAddress leadDisplayAddress = display.getLeadDisplayAddress();
+ if (leadDisplayAddress == null) {
+ display.setLeadDisplayId(NO_LEAD_DISPLAY);
+ continue;
+ }
+ Display leadDisplay = getByAddress(leadDisplayAddress);
+ if (leadDisplay == null) {
+ throw new IllegalArgumentException("Cannot find a lead display whose address is "
+ + leadDisplayAddress);
+ }
+ if (!TextUtils.equals(display.getDisplayGroupName(),
+ leadDisplay.getDisplayGroupName())) {
+ throw new IllegalArgumentException("Lead display(" + leadDisplay + ") should be in "
+ + "the same display group of the display(" + display + ")");
+ }
+ if (hasCyclicLeadDisplay(display)) {
+ throw new IllegalArgumentException("Display(" + display + ") has a cyclic lead "
+ + "display");
+ }
+ display.setLeadDisplayId(leadDisplay.getLogicalDisplayId());
+ }
+ }
+
+ /**
* @param address The address to check.
*
* @return True if the specified address is used in this layout.
@@ -208,6 +254,20 @@
return mDisplays.size();
}
+ private boolean hasCyclicLeadDisplay(Display display) {
+ ArraySet<Display> visited = new ArraySet<>();
+
+ while (display != null) {
+ if (visited.contains(display)) {
+ return true;
+ }
+ visited.add(display);
+ DisplayAddress leadDisplayAddress = display.getLeadDisplayAddress();
+ display = leadDisplayAddress == null ? null : getByAddress(leadDisplayAddress);
+ }
+ return false;
+ }
+
/**
* Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s.
*/
@@ -240,8 +300,9 @@
@Nullable
private final String mThermalBrightnessThrottlingMapId;
- // The ID of the lead display that this display will follow in a layout. -1 means no lead.
- private final int mLeadDisplayId;
+ // The address of the lead display that is specified in display-layout-configuration.
+ @Nullable
+ private final DisplayAddress mLeadDisplayAddress;
// Refresh rate zone id for specific layout
@Nullable
@@ -250,9 +311,13 @@
@Nullable
private final String mThermalRefreshRateThrottlingMapId;
+ // The ID of the lead display that this display will follow in a layout. -1 means no lead.
+ // This is determined using {@code mLeadDisplayAddress}.
+ private int mLeadDisplayId;
+
private Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled,
@NonNull String displayGroupName, String brightnessThrottlingMapId, int position,
- int leadDisplayId, @Nullable String refreshRateZoneId,
+ @Nullable DisplayAddress leadDisplayAddress, @Nullable String refreshRateZoneId,
@Nullable String refreshRateThermalThrottlingMapId) {
mAddress = address;
mLogicalDisplayId = logicalDisplayId;
@@ -260,9 +325,10 @@
mDisplayGroupName = displayGroupName;
mPosition = position;
mThermalBrightnessThrottlingMapId = brightnessThrottlingMapId;
+ mLeadDisplayAddress = leadDisplayAddress;
mRefreshRateZoneId = refreshRateZoneId;
mThermalRefreshRateThrottlingMapId = refreshRateThermalThrottlingMapId;
- mLeadDisplayId = leadDisplayId;
+ mLeadDisplayId = NO_LEAD_DISPLAY;
}
@Override
@@ -276,6 +342,7 @@
+ ", mThermalBrightnessThrottlingMapId: " + mThermalBrightnessThrottlingMapId
+ ", mRefreshRateZoneId: " + mRefreshRateZoneId
+ ", mLeadDisplayId: " + mLeadDisplayId
+ + ", mLeadDisplayAddress: " + mLeadDisplayAddress
+ ", mThermalRefreshRateThrottlingMapId: " + mThermalRefreshRateThrottlingMapId
+ "}";
}
@@ -297,6 +364,7 @@
otherDisplay.mThermalBrightnessThrottlingMapId)
&& Objects.equals(otherDisplay.mRefreshRateZoneId, this.mRefreshRateZoneId)
&& this.mLeadDisplayId == otherDisplay.mLeadDisplayId
+ && Objects.equals(mLeadDisplayAddress, otherDisplay.mLeadDisplayAddress)
&& Objects.equals(mThermalRefreshRateThrottlingMapId,
otherDisplay.mThermalRefreshRateThrottlingMapId);
}
@@ -309,9 +377,10 @@
result = 31 * result + mLogicalDisplayId;
result = 31 * result + mDisplayGroupName.hashCode();
result = 31 * result + mAddress.hashCode();
- result = 31 * result + mThermalBrightnessThrottlingMapId.hashCode();
+ result = 31 * result + Objects.hashCode(mThermalBrightnessThrottlingMapId);
result = 31 * result + Objects.hashCode(mRefreshRateZoneId);
result = 31 * result + mLeadDisplayId;
+ result = 31 * result + Objects.hashCode(mLeadDisplayAddress);
result = 31 * result + Objects.hashCode(mThermalRefreshRateThrottlingMapId);
return result;
}
@@ -360,8 +429,20 @@
return mLeadDisplayId;
}
+ /**
+ * @return Display address of the display that this one follows.
+ */
+ @Nullable
+ public DisplayAddress getLeadDisplayAddress() {
+ return mLeadDisplayAddress;
+ }
+
public String getRefreshRateThermalThrottlingMapId() {
return mThermalRefreshRateThrottlingMapId;
}
+
+ private void setLeadDisplayId(int id) {
+ mLeadDisplayId = id;
+ }
}
}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index d3371b1..080b947 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -228,10 +228,15 @@
mIsSafeMode = safeMode;
initialize();
- try {
- Typeface.setSystemFontMap(getCurrentFontMap());
- } catch (IOException | ErrnoException e) {
- Slog.w(TAG, "Failed to set system font map of system_server");
+ // Set system font map only if there is updatable font directory.
+ // If there is no updatable font directory, `initialize` will have already loaded the
+ // system font map, so there's no need to set the system font map again here.
+ if (mUpdatableFontDir != null) {
+ try {
+ Typeface.setSystemFontMap(getCurrentFontMap());
+ } catch (IOException | ErrnoException e) {
+ Slog.w(TAG, "Failed to set system font map of system_server");
+ }
}
}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 3ac1594..63fded1 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -28,6 +28,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.settings.SettingsEnums;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -1168,6 +1169,8 @@
if (targetDevice != null) {
intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, targetDevice.getIdentifier());
+ intent.putExtra(
+ Settings.EXTRA_ENTRYPOINT, SettingsEnums.KEYBOARD_CONFIGURED_NOTIFICATION);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index eb1a0e2..09f373f 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -421,6 +421,9 @@
android.hardware.contexthub.IContextHubCallback.Stub {
private final int mContextHubId;
private final ICallback mCallback;
+ // 9a17008d-6bf1-445a-9011-6d21bd985b6c
+ private static final byte[] UUID = {-102, 23, 0, -115, 107, -15, 68, 90,
+ -112, 17, 109, 33, -67, -104, 91, 108};
ContextHubAidlCallback(int contextHubId, ICallback callback) {
mContextHubId = contextHubId;
@@ -463,6 +466,10 @@
// TODO(271471342): Implement
}
+ public byte[] getUuid() {
+ return UUID;
+ }
+
@Override
public String getInterfaceHash() {
return android.hardware.contexthub.IContextHubCallback.HASH;
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index 46f486d..f572845 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -311,7 +311,7 @@
@Nullable
private static synchronized IGateKeeperService getGatekeeperService() {
- final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
+ final IBinder service = ServiceManager.waitForService(Context.GATEKEEPER_SERVICE);
if (service == null) {
Slog.e(TAG, "Unable to acquire GateKeeperService");
return null;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 97dc062..fd4176a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -311,8 +311,9 @@
super.onBootPhase(phase);
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mLockSettingsService.migrateOldDataAfterSystemReady();
- mLockSettingsService.loadEscrowData();
mLockSettingsService.deleteRepairModePersistentDataIfNeeded();
+ } else if (phase == PHASE_BOOT_COMPLETED) {
+ mLockSettingsService.loadEscrowData();
}
}
@@ -843,7 +844,6 @@
mHasSecureLockScreen = mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN);
migrateOldData();
- getGateKeeperService();
getAuthSecretHal();
mDeviceProvisionedObserver.onSystemReady();
@@ -2599,7 +2599,7 @@
return mGateKeeperService;
}
- final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
+ final IBinder service = ServiceManager.waitForService(Context.GATEKEEPER_SERVICE);
if (service != null) {
try {
service.linkToDeath(new GateKeeperDiedRecipient(), 0);
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index c59b733..8149847 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -116,6 +116,7 @@
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + getDebugString());
prefix += " ";
+
if (mProviderInfo == null) {
pw.println(prefix + "<provider info not received, yet>");
} else if (mProviderInfo.getRoutes().isEmpty()) {
@@ -125,6 +126,17 @@
pw.printf("%s%s | %s\n", prefix, route.getId(), route.getName());
}
}
+
+ pw.println(prefix + "Active routing sessions:");
+ synchronized (mLock) {
+ if (mSessionInfos.isEmpty()) {
+ pw.println(prefix + " <no active routing sessions>");
+ } else {
+ for (RoutingSessionInfo routingSessionInfo : mSessionInfos) {
+ routingSessionInfo.dump(pw, prefix + " ");
+ }
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 030c96e..bfc4f53 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -251,6 +251,11 @@
}
@Override
+ protected boolean allowRebindForParentUser() {
+ return true;
+ }
+
+ @Override
protected String getRequiredPermission() {
return null;
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index f29c285..c6f6fe2 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1372,7 +1372,9 @@
protected void rebindServices(boolean forceRebind, int userToRebind) {
if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
IntArray userIds = mUserProfiles.getCurrentProfileIds();
- if (userToRebind != USER_ALL) {
+ boolean rebindAllCurrentUsers = mUserProfiles.isProfileUser(userToRebind)
+ && allowRebindForParentUser();
+ if (userToRebind != USER_ALL && !rebindAllCurrentUsers) {
userIds = new IntArray(1);
userIds.add(userToRebind);
}
@@ -1762,6 +1764,13 @@
return true;
}
+ /**
+ * Returns true if services in the parent user should be rebound
+ * when rebindServices is called with a profile userId.
+ * Must be false for NotificationAssistants.
+ */
+ protected abstract boolean allowRebindForParentUser();
+
public class ManagedServiceInfo implements IBinder.DeathRecipient {
public IInterface service;
public ComponentName component;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 624a33b..1bc681a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4442,7 +4442,7 @@
// Remove background token before returning notification to untrusted app, this
// ensures the app isn't able to perform background operations that are
// associated with notification interactions.
- notification.setAllowlistToken(null);
+ notification.clearAllowlistToken();
return new StatusBarNotification(
sbn.getPackageName(),
sbn.getOpPkg(),
@@ -7005,7 +7005,7 @@
*/
private boolean canBeNonDismissible(ApplicationInfo ai, Notification notification) {
return notification.isMediaNotification() || isEnterpriseExempted(ai)
- || isCallNotification(ai.packageName, ai.uid, notification)
+ || notification.isStyle(Notification.CallStyle.class)
|| isDefaultSearchSelectorPackage(ai.packageName);
}
@@ -10501,6 +10501,11 @@
}
@Override
+ protected boolean allowRebindForParentUser() {
+ return false;
+ }
+
+ @Override
protected String getRequiredPermission() {
// only signature/privileged apps can be bound.
return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
@@ -11045,6 +11050,11 @@
}
@Override
+ protected boolean allowRebindForParentUser() {
+ return true;
+ }
+
+ @Override
public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
super.onPackagesChanged(removingPackage, pkgList, uidList);
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 5ca882c..b015a72 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -30,6 +30,7 @@
import android.os.Bundle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
+import android.util.Log;
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags;
@@ -48,6 +49,8 @@
*/
interface NotificationRecordLogger {
+ static final String TAG = "NotificationRecordLogger";
+
// The high-level interface used by clients.
/**
@@ -228,51 +231,40 @@
@NotificationStats.DismissalSurface int surface) {
// Shouldn't be possible to get a non-dismissed notification here.
if (surface == NotificationStats.DISMISSAL_NOT_DISMISSED) {
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected surface " + surface);
- }
+ Log.wtf(TAG, "Unexpected surface: " + surface + " with reason " + reason);
return INVALID;
}
- // Most cancel reasons do not have a meaningful surface. Reason codes map directly
- // to NotificationCancelledEvent codes.
- if (surface == NotificationStats.DISMISSAL_OTHER) {
+
+ // User cancels have a meaningful surface, which we differentiate by. See b/149038335
+ // for caveats.
+ if (reason == REASON_CANCEL) {
+ switch (surface) {
+ case NotificationStats.DISMISSAL_PEEK:
+ return NOTIFICATION_CANCEL_USER_PEEK;
+ case NotificationStats.DISMISSAL_AOD:
+ return NOTIFICATION_CANCEL_USER_AOD;
+ case NotificationStats.DISMISSAL_SHADE:
+ return NOTIFICATION_CANCEL_USER_SHADE;
+ case NotificationStats.DISMISSAL_BUBBLE:
+ return NOTIFICATION_CANCEL_USER_BUBBLE;
+ case NotificationStats.DISMISSAL_LOCKSCREEN:
+ return NOTIFICATION_CANCEL_USER_LOCKSCREEN;
+ case NotificationStats.DISMISSAL_OTHER:
+ return NOTIFICATION_CANCEL_USER_OTHER;
+ default:
+ Log.wtf(TAG, "Unexpected surface: " + surface + " with reason " + reason);
+ return INVALID;
+ }
+ } else {
if ((REASON_CLICK <= reason) && (reason <= REASON_CLEAR_DATA)) {
return NotificationCancelledEvent.values()[reason];
}
if (reason == REASON_ASSISTANT_CANCEL) {
return NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT;
}
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected cancel reason " + reason);
- }
+ Log.wtf(TAG, "Unexpected reason: " + reason + " with surface " + surface);
return INVALID;
}
- // User cancels have a meaningful surface, which we differentiate by. See b/149038335
- // for caveats.
- if (reason != REASON_CANCEL) {
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected cancel with surface " + reason);
- }
- return INVALID;
- }
- switch (surface) {
- case NotificationStats.DISMISSAL_PEEK:
- return NOTIFICATION_CANCEL_USER_PEEK;
- case NotificationStats.DISMISSAL_AOD:
- return NOTIFICATION_CANCEL_USER_AOD;
- case NotificationStats.DISMISSAL_SHADE:
- return NOTIFICATION_CANCEL_USER_SHADE;
- case NotificationStats.DISMISSAL_BUBBLE:
- return NOTIFICATION_CANCEL_USER_BUBBLE;
- case NotificationStats.DISMISSAL_LOCKSCREEN:
- return NOTIFICATION_CANCEL_USER_LOCKSCREEN;
- default:
- if (NotificationManagerService.DBG) {
- throw new IllegalArgumentException("Unexpected surface for user-dismiss "
- + reason);
- }
- return INVALID;
- }
}
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 838a0fb..1818d25 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -30,9 +30,9 @@
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
-import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
-import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -164,6 +164,9 @@
static final int DEFAULT_BUBBLE_PREFERENCE = BUBBLE_PREFERENCE_NONE;
static final boolean DEFAULT_MEDIA_NOTIFICATION_FILTERING = true;
+ private static final int NOTIFICATION_UPDATE_LOG_SUBTYPE_FROM_APP = 0;
+ private static final int NOTIFICATION_UPDATE_LOG_SUBTYPE_FROM_USER = 1;
+
/**
* Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
* fields.
@@ -1110,12 +1113,20 @@
if (!channel.equals(updatedChannel)) {
// only log if there are real changes
MetricsLogger.action(getChannelLog(updatedChannel, pkg)
- .setSubtype(fromUser ? 1 : 0));
+ .setSubtype(fromUser ? NOTIFICATION_UPDATE_LOG_SUBTYPE_FROM_USER
+ : NOTIFICATION_UPDATE_LOG_SUBTYPE_FROM_APP));
mNotificationChannelLogger.logNotificationChannelModified(updatedChannel, uid, pkg,
NotificationChannelLogger.getLoggingImportance(channel), fromUser);
changed = true;
}
+ if (fromUser && SystemUiSystemPropertiesFlags.getResolver().isEnabled(
+ NotificationFlags.PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS)) {
+ updateChildrenConversationChannels(r, channel, updatedChannel);
+ // No need to update changed or needsDndChanged as the child channel(s) cannot be
+ // relevantly affected without the parent channel already having been.
+ }
+
if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
|| channel.getImportance() != updatedChannel.getImportance()) {
needsDndChange = true;
@@ -1130,6 +1141,101 @@
}
}
+ /**
+ * Updates conversation channels after user changes to their parent channel. See
+ * {@link #maybeUpdateChildConversationChannel}.
+ */
+ @GuardedBy("mPackagePreferences")
+ private void updateChildrenConversationChannels(@NonNull PackagePreferences packagePreferences,
+ @NonNull NotificationChannel oldParent, @NonNull NotificationChannel updatedParent) {
+ if (oldParent.equals(updatedParent)) {
+ return;
+ }
+ if (oldParent.isConversation()) {
+ return; // Can't have children.
+ }
+ for (NotificationChannel channel : packagePreferences.channels.values()) {
+ // Include deleted -- otherwise they will have old settings if later resurrected.
+ // Include demoted -- still attached to their parents.
+ if (channel.isConversation()
+ && oldParent.getId().equals(channel.getParentChannelId())) {
+ maybeUpdateChildConversationChannel(packagePreferences.pkg, packagePreferences.uid,
+ channel, oldParent, updatedParent);
+ }
+ }
+ }
+
+ /**
+ * Apply the diff between {@code oldParent} and {@code updatedParent} to the child
+ * {@code conversation} channel. Only fields that are not locked on the conversation channel
+ * (see {@link NotificationChannel#LOCKABLE_FIELDS }) will be updated (so that we don't override
+ * previous explicit user choices).
+ *
+ * <p>This will also log the change as if it was {@code fromUser=true}.
+ */
+ @GuardedBy("mPackagePreferences")
+ private void maybeUpdateChildConversationChannel(String pkg, int uid,
+ @NonNull NotificationChannel conversation, @NonNull NotificationChannel oldParent,
+ @NonNull NotificationChannel updatedParent) {
+ boolean changed = false;
+ int oldLoggingImportance = NotificationChannelLogger.getLoggingImportance(conversation);
+
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_PRIORITY) == 0
+ && oldParent.canBypassDnd() != updatedParent.canBypassDnd()) {
+ conversation.setBypassDnd(updatedParent.canBypassDnd());
+ changed = true;
+ }
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_VISIBILITY) == 0
+ && oldParent.getLockscreenVisibility()
+ != updatedParent.getLockscreenVisibility()) {
+ conversation.setLockscreenVisibility(updatedParent.getLockscreenVisibility());
+ changed = true;
+ }
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
+ && oldParent.getImportance() != updatedParent.getImportance()) {
+ conversation.setImportance(updatedParent.getImportance());
+ changed = true;
+ }
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_LIGHTS) == 0
+ && (oldParent.shouldShowLights() != updatedParent.shouldShowLights()
+ || oldParent.getLightColor() != updatedParent.getLightColor())) {
+ conversation.enableLights(updatedParent.shouldShowLights());
+ conversation.setLightColor(updatedParent.getLightColor());
+ changed = true;
+ }
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_SOUND) == 0
+ && !Objects.equals(oldParent.getSound(), updatedParent.getSound())) {
+ conversation.setSound(updatedParent.getSound(), updatedParent.getAudioAttributes());
+ changed = true;
+ }
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_VIBRATION) == 0
+ && (!Arrays.equals(oldParent.getVibrationPattern(),
+ updatedParent.getVibrationPattern())
+ || oldParent.shouldVibrate() != updatedParent.shouldVibrate())) {
+ // enableVibration must be 2nd because setVibrationPattern may toggle it.
+ conversation.setVibrationPattern(updatedParent.getVibrationPattern());
+ conversation.enableVibration(updatedParent.shouldVibrate());
+ changed = true;
+ }
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_SHOW_BADGE) == 0
+ && oldParent.canShowBadge() != updatedParent.canShowBadge()) {
+ conversation.setShowBadge(updatedParent.canShowBadge());
+ changed = true;
+ }
+ if ((conversation.getUserLockedFields() & NotificationChannel.USER_LOCKED_ALLOW_BUBBLE) == 0
+ && oldParent.getAllowBubbles() != updatedParent.getAllowBubbles()) {
+ conversation.setAllowBubbles(updatedParent.getAllowBubbles());
+ changed = true;
+ }
+
+ if (changed) {
+ MetricsLogger.action(getChannelLog(conversation, pkg).setSubtype(
+ NOTIFICATION_UPDATE_LOG_SUBTYPE_FROM_USER));
+ mNotificationChannelLogger.logNotificationChannelModified(conversation, uid, pkg,
+ oldLoggingImportance, /* fromUser= */ true);
+ }
+ }
+
@Override
public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId,
boolean includeDeleted) {
@@ -1838,8 +1944,8 @@
}
}
- @VisibleForTesting
- void lockFieldsForUpdateLocked(NotificationChannel original, NotificationChannel update) {
+ private void lockFieldsForUpdateLocked(NotificationChannel original,
+ NotificationChannel update) {
if (original.canBypassDnd() != update.canBypassDnd()) {
update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
}
diff --git a/services/core/java/com/android/server/pm/DefaultAppProvider.java b/services/core/java/com/android/server/pm/DefaultAppProvider.java
index c18d0e9..fc61451 100644
--- a/services/core/java/com/android/server/pm/DefaultAppProvider.java
+++ b/services/core/java/com/android/server/pm/DefaultAppProvider.java
@@ -24,14 +24,10 @@
import android.os.UserHandle;
import android.util.Slog;
-import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.CollectionUtils;
import com.android.server.FgThread;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -70,27 +66,19 @@
* Set the package name of the default browser.
*
* @param packageName package name of the default browser, or {@code null} to unset
- * @param async whether the operation should be asynchronous
* @param userId the user ID
- * @return whether the default browser was successfully set.
*/
- public boolean setDefaultBrowser(@Nullable String packageName, boolean async,
- @UserIdInt int userId) {
- if (userId == UserHandle.USER_ALL) {
- return false;
- }
+ public void setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
final RoleManager roleManager = mRoleManagerSupplier.get();
if (roleManager == null) {
- return false;
+ return;
}
final UserHandle user = UserHandle.of(userId);
final Executor executor = FgThread.getExecutor();
- final AndroidFuture<Void> future = new AndroidFuture<>();
final Consumer<Boolean> callback = successful -> {
- if (successful) {
- future.complete(null);
- } else {
- future.completeExceptionally(new RuntimeException());
+ if (!successful) {
+ Slog.e(PackageManagerService.TAG, "Failed to set default browser to "
+ + packageName);
}
};
final long identity = Binder.clearCallingIdentity();
@@ -102,19 +90,9 @@
roleManager.clearRoleHoldersAsUser(RoleManager.ROLE_BROWSER, 0, user, executor,
callback);
}
- if (!async) {
- try {
- future.get(5, TimeUnit.SECONDS);
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- Slog.e(PackageManagerService.TAG, "Exception while setting default browser: "
- + packageName, e);
- return false;
- }
- }
} finally {
Binder.restoreCallingIdentity(identity);
}
- return true;
}
/**
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ae169318..12f3aa9 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -372,7 +372,7 @@
filter.addDataScheme("package");
mContext.registerReceiverAsUser(mPackageRemovedListener, UserHandle.ALL, filter,
/* broadcastPermission= */ null, mCallbackHandler);
- mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
+ mPackageMonitor.register(mContext, UserHandle.ALL, mCallbackHandler);
mIsWatchingPackageBroadcasts = true;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index af6c1a2..3e48304 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2998,12 +2998,14 @@
// action. When the targetPkg is set, it sends the broadcast to specific app, e.g.
// installer app or null for registered apps. The callback only need to send back to the
// registered apps so we check the null condition here.
- notifyPackageMonitor(action, pkg, extras, userIds);
+ notifyPackageMonitor(action, pkg, extras, userIds, instantUserIds);
}
}
- void notifyPackageMonitor(String action, String pkg, Bundle extras, int[] userIds) {
- mPackageMonitorCallbackHelper.notifyPackageMonitor(action, pkg, extras, userIds);
+ void notifyPackageMonitor(String action, String pkg, Bundle extras, int[] userIds,
+ int[] instantUserIds) {
+ mPackageMonitorCallbackHelper.notifyPackageMonitor(action, pkg, extras, userIds,
+ instantUserIds);
}
void notifyResourcesChanged(boolean mediaStatus, boolean replacing,
@@ -3423,6 +3425,18 @@
// within these users.
mPermissionManager.restoreDelayedRuntimePermissions(packageName, userId);
+ // Restore default browser setting if it is now installed.
+ String defaultBrowser;
+ synchronized (mLock) {
+ defaultBrowser = mSettings.getPendingDefaultBrowserLPr(userId);
+ }
+ if (Objects.equals(packageName, defaultBrowser)) {
+ mDefaultAppProvider.setDefaultBrowser(packageName, userId);
+ synchronized (mLock) {
+ mSettings.removePendingDefaultBrowserLPw(userId);
+ }
+ }
+
// Persistent preferred activity might have came into effect due to this
// install.
mPreferredActivityHelper.updateDefaultHomeNotLocked(snapshotComputer(), userId);
@@ -4053,7 +4067,7 @@
packageName, dontKillApp, componentNames, packageUid, reason, userIds,
instantUserIds, broadcastAllowList));
mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames,
- packageUid, reason, userIds);
+ packageUid, reason, userIds, instantUserIds);
}
/**
@@ -4297,6 +4311,7 @@
mAppsFilter.onUserDeleted(snapshotComputer(), userId);
}
mInstantAppRegistry.onUserRemoved(userId);
+ mPackageMonitorCallbackHelper.onUserRemoved(userId);
}
/**
@@ -6644,7 +6659,7 @@
@Override
public String removeLegacyDefaultBrowserPackageName(int userId) {
synchronized (mLock) {
- return mSettings.removeDefaultBrowserPackageNameLPw(userId);
+ return mSettings.removePendingDefaultBrowserLPw(userId);
}
}
@@ -7520,8 +7535,8 @@
return mDefaultAppProvider.getDefaultBrowser(userId);
}
- void setDefaultBrowser(@Nullable String packageName, boolean async, @UserIdInt int userId) {
- mDefaultAppProvider.setDefaultBrowser(packageName, async, userId);
+ void setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
+ mDefaultAppProvider.setDefaultBrowser(packageName, userId);
}
PackageUsage getPackageUsage() {
diff --git a/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java b/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
index c582321..1e3fab6 100644
--- a/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
+++ b/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
@@ -68,6 +68,29 @@
}
}
+ public void onUserRemoved(int userId) {
+ ArrayList<IRemoteCallback> targetUnRegisteredCallbacks = null;
+ synchronized (mLock) {
+ int registerCount = mCallbacks.getRegisteredCallbackCount();
+ for (int i = 0; i < registerCount; i++) {
+ int registerUserId = (int) mCallbacks.getRegisteredCallbackCookie(i);
+ if (registerUserId == userId) {
+ IRemoteCallback callback = mCallbacks.getRegisteredCallbackItem(i);
+ if (targetUnRegisteredCallbacks == null) {
+ targetUnRegisteredCallbacks = new ArrayList<>();
+ }
+ targetUnRegisteredCallbacks.add(callback);
+ }
+ }
+ }
+ if (targetUnRegisteredCallbacks != null && targetUnRegisteredCallbacks.size() > 0) {
+ int count = targetUnRegisteredCallbacks.size();
+ for (int i = 0; i < count; i++) {
+ unregisterPackageMonitorCallback(targetUnRegisteredCallbacks.get(i));
+ }
+ }
+ }
+
public void notifyPackageAddedForNewUsers(String packageName,
@AppIdInt int appId, @NonNull int[] userIds, @NonNull int[] instantUserIds,
int dataLoaderType) {
@@ -78,7 +101,7 @@
extras.putInt(Intent.EXTRA_UID, uid);
extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED, packageName, extras ,
- userIds /* userIds */);
+ userIds /* userIds */, instantUserIds);
}
public void notifyResourcesChanged(boolean mediaStatus, boolean replacing,
@@ -91,11 +114,13 @@
}
String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
: Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
- notifyPackageMonitor(action, null /* pkg */, extras, null /* userIds */);
+ notifyPackageMonitor(action, null /* pkg */, extras, null /* userIds */,
+ null /* instantUserIds */);
}
public void notifyPackageChanged(String packageName, boolean dontKillApp,
- ArrayList<String> componentNames, int packageUid, String reason, int[] userIds) {
+ ArrayList<String> componentNames, int packageUid, String reason, int[] userIds,
+ int[] instantUserIds) {
Bundle extras = new Bundle(4);
extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
String[] nameList = new String[componentNames.size()];
@@ -106,11 +131,12 @@
if (reason != null) {
extras.putString(Intent.EXTRA_REASON, reason);
}
- notifyPackageMonitor(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, userIds);
+ notifyPackageMonitor(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, userIds,
+ instantUserIds);
}
public void notifyPackageMonitor(String action, String pkg, Bundle extras,
- int[] userIds) {
+ int[] userIds, int[] instantUserIds) {
if (!isAllowedCallbackAction(action)) {
return;
}
@@ -122,7 +148,12 @@
} else {
resolvedUserIds = userIds;
}
- doNotifyCallbacks(action, pkg, extras, resolvedUserIds);
+
+ if (ArrayUtils.isEmpty(instantUserIds)) {
+ doNotifyCallbacks(action, pkg, extras, resolvedUserIds);
+ } else {
+ doNotifyCallbacks(action, pkg, extras, instantUserIds);
+ }
} catch (RemoteException e) {
// do nothing
}
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 6e273cf..571aab4 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -585,7 +585,17 @@
(parser1, userId1) -> {
final String defaultBrowser = Settings.readDefaultApps(parser1);
if (defaultBrowser != null) {
- mPm.setDefaultBrowser(defaultBrowser, false, userId1);
+ final PackageStateInternal packageState = mPm.snapshotComputer()
+ .getPackageStateInternal(defaultBrowser);
+ if (packageState != null
+ && packageState.getUserStateOrDefault(userId1).isInstalled()) {
+ mPm.setDefaultBrowser(defaultBrowser, userId1);
+ } else {
+ synchronized (mPm.mLock) {
+ mPm.mSettings.setPendingDefaultBrowserLPw(defaultBrowser,
+ userId1);
+ }
+ }
}
});
} catch (Exception e) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 87f9126..60c5852 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -518,9 +518,11 @@
private final WatchedArrayMap<String, String> mRenamedPackages =
new WatchedArrayMap<String, String>();
- // For every user, it is used to find the package name of the default Browser App.
+ // For every user, it is used to find the package name of the default browser app pending to be
+ // applied, either on first boot after upgrade, or after backup & restore but before app is
+ // installed.
@Watched
- final WatchedSparseArray<String> mDefaultBrowserApp = new WatchedSparseArray<String>();
+ final WatchedSparseArray<String> mPendingDefaultBrowser = new WatchedSparseArray<>();
// TODO(b/161161364): This seems unused, and is probably not relevant in the new API, but should
// verify.
@@ -593,7 +595,7 @@
mAppIds.registerObserver(mObserver);
mRenamedPackages.registerObserver(mObserver);
mNextAppLinkGeneration.registerObserver(mObserver);
- mDefaultBrowserApp.registerObserver(mObserver);
+ mPendingDefaultBrowser.registerObserver(mObserver);
mPendingPackages.registerObserver(mObserver);
mPastSignatures.registerObserver(mObserver);
mKeySetRefs.registerObserver(mObserver);
@@ -788,7 +790,7 @@
mRenamedPackages.snapshot(r.mRenamedPackages);
mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration);
- mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp);
+ mPendingDefaultBrowser.snapshot(r.mPendingDefaultBrowser);
// mReadMessages
mPendingPackages = r.mPendingPackagesSnapshot.snapshot();
mPendingPackagesSnapshot = new SnapshotCache.Sealed<>();
@@ -1509,8 +1511,16 @@
return cpir;
}
- String removeDefaultBrowserPackageNameLPw(int userId) {
- return (userId == UserHandle.USER_ALL) ? null : mDefaultBrowserApp.removeReturnOld(userId);
+ String getPendingDefaultBrowserLPr(int userId) {
+ return mPendingDefaultBrowser.get(userId);
+ }
+
+ void setPendingDefaultBrowserLPw(String defaultBrowser, int userId) {
+ mPendingDefaultBrowser.put(userId, defaultBrowser);
+ }
+
+ String removePendingDefaultBrowserLPw(int userId) {
+ return mPendingDefaultBrowser.removeReturnOld(userId);
}
private File getUserSystemDirectory(int userId) {
@@ -1695,7 +1705,7 @@
throws XmlPullParserException, IOException {
String defaultBrowser = readDefaultApps(parser);
if (defaultBrowser != null) {
- mDefaultBrowserApp.put(userId, defaultBrowser);
+ mPendingDefaultBrowser.put(userId, defaultBrowser);
}
}
@@ -2105,7 +2115,7 @@
void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
throws IllegalArgumentException, IllegalStateException, IOException {
- String defaultBrowser = mDefaultBrowserApp.get(userId);
+ String defaultBrowser = mPendingDefaultBrowser.get(userId);
writeDefaultApps(serializer, defaultBrowser);
}
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 89aff9e..893bc11a 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -633,7 +633,8 @@
(callingUid, intentExtras) -> BroadcastHelper.filterExtrasChangedPackageList(
mPm.snapshotComputer(), callingUid, intentExtras),
options));
- mPm.notifyPackageMonitor(intent, null /* pkg */, extras, new int[]{userId});
+ mPm.notifyPackageMonitor(intent, null /* pkg */, extras, new int[]{userId},
+ null /* instantUserIds */);
}
/**
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index a622d07..01e0fbd 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -88,6 +88,15 @@
"include-filter": "android.uidmigration.cts"
}
]
+ },
+ {
+ "name": "CtsAppSecurityHostTestCases",
+ "file_patterns": ["(/|^)PackageMonitorCallbackHelper\\.java"],
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.EphemeralTest#testGetSearchableInfo"
+ }
+ ]
}
],
"presubmit-large": [
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 7198de2..3a1fd7c 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -589,27 +589,14 @@
final PackageVerificationResponse response = new PackageVerificationResponse(
verificationCodeAtTimeout, requiredUid);
- if (streaming) {
- // For streaming installations, count verification timeout from the broadcast.
- startVerificationTimeoutCountdown(verificationId, streaming, response,
- verificationTimeout);
- }
+ startVerificationTimeoutCountdown(verificationId, streaming, response,
+ verificationTimeout);
// Send the intent to the required verification agent, but only start the
// verification timeout after the target BroadcastReceivers have run.
mPm.mContext.sendOrderedBroadcastAsUser(requiredIntent, verifierUser,
receiverPermission, AppOpsManager.OP_NONE, options.toBundle(),
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!streaming) {
- // For NON-streaming installations, count verification timeout from
- // the broadcast was processed by all receivers.
- startVerificationTimeoutCountdown(verificationId, streaming,
- response, verificationTimeout);
- }
- }
- }, null, 0, null, null);
+ null, null, 0, null, null);
}
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 46b3db8..402bb59 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3304,8 +3304,10 @@
minLinearBrightness, maxLinearBrightness);
mDisplayManager.setBrightness(screenDisplayId, adjustedLinearBrightness);
- startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
- UserHandle.CURRENT_OR_SELF);
+ Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
+ intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true);
+ startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
}
return true;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
@@ -3535,16 +3537,12 @@
}
private void requestBugreportForTv() {
- if ("1".equals(SystemProperties.get("ro.debuggable"))
- || Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) {
- try {
- if (!ActivityManager.getService().launchBugReportHandlerApp()) {
- ActivityManager.getService().requestInteractiveBugReport();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Error taking bugreport", e);
+ try {
+ if (!ActivityManager.getService().launchBugReportHandlerApp()) {
+ ActivityManager.getService().requestInteractiveBugReport();
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error taking bugreport", e);
}
}
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 32104f6..80c21f4 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -16246,7 +16246,7 @@
}
NP = in.readInt();
- if (NP > 1000) {
+ if (NP > 10000) {
throw new ParcelFormatException("File corrupt: too many processes " + NP);
}
for (int ip = 0; ip < NP; ip++) {
diff --git a/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java b/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
index ac97038..b178269 100644
--- a/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
+++ b/services/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java
@@ -98,7 +98,7 @@
Preconditions.checkState(!mRegistered);
mRegistered = true;
- mPackageMonitor.register(mContext, UserHandle.ALL, /*externalStorage=*/ true, mHandler);
+ mPackageMonitor.register(mContext, UserHandle.ALL, mHandler);
mServiceSupplier.register(this);
onServiceChanged(false);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d2715b6..455e7ae 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -698,6 +698,10 @@
mRequest.intent, caller, callingUid);
}
+ if (mRequest.intent != null) {
+ mRequest.componentSpecified |= mRequest.intent.getComponent() != null;
+ }
+
// If the caller hasn't already resolved the activity, we're willing
// to do so here. If the caller is already holding the WM lock here,
// and we need to check dynamic Uri permissions, then we're forced
@@ -1993,11 +1997,7 @@
}
}
- boolean shouldBlockActivityStart = true;
- // Used for logging/toasts. Would we block the start if target sdk was U and feature was
- // enabled?
- boolean wouldBlockActivityStartIgnoringFlags = true;
-
+ Pair<Boolean, Boolean> pair = null;
if (mSourceRecord != null) {
boolean passesAsmChecks = true;
Task sourceTask = mSourceRecord.getTask();
@@ -2013,14 +2013,25 @@
if (passesAsmChecks) {
Task taskToCheck = taskToFront ? sourceTask : targetTask;
- // first == false means Should Block
- // second == false means Would Block disregarding flags
- Pair<Boolean, Boolean> pair = ActivityTaskSupervisor
+ pair = ActivityTaskSupervisor
.doesTopActivityMatchingUidExistForAsm(taskToCheck, mSourceRecord.getUid(),
mSourceRecord);
- shouldBlockActivityStart = !pair.first;
- wouldBlockActivityStartIgnoringFlags = !pair.second;
}
+ } else if (!taskToFront) {
+ // We don't have a sourceRecord, and we're launching into an existing task.
+ // Allow if callingUid is top of stack.
+ pair = ActivityTaskSupervisor
+ .doesTopActivityMatchingUidExistForAsm(targetTask, mCallingUid,
+ /*sourceRecord*/null);
+ }
+
+ boolean shouldBlockActivityStart = true;
+ if (pair != null) {
+ // We block if feature flag is enabled
+ shouldBlockActivityStart = !pair.first;
+ // Used for logging/toasts. Would we block if target sdk was U and feature was
+ // enabled? If so, we can't return here but we also might not block at the end
+ boolean wouldBlockActivityStartIgnoringFlags = !pair.second;
if (!wouldBlockActivityStartIgnoringFlags) {
return true;
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index 0273a30..ad5f442 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -160,7 +160,11 @@
* @param r activity record for which the warning may be displayed
*/
public void showDeprecatedTargetDialogIfNeeded(ActivityRecord r) {
- if (r.info.applicationInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT) {
+ // The warning dialog can be disabled for debugging or testing purposes
+ final boolean disableDeprecatedTargetSdkDialog = SystemProperties.getBoolean(
+ "debug.wm.disable_deprecated_target_sdk_dialog", false);
+ if (r.info.applicationInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT
+ && !disableDeprecatedTargetSdkDialog) {
mUiHandler.showDeprecatedTargetDialog(r);
}
}
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 6a7e764..2ecbf8a 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -166,7 +166,7 @@
+ "%d to new bounds %s and/or orientation %d.",
mDisplayContent.getDisplayId(), recordedContentBounds,
recordedContentOrientation);
- updateMirroredSurface(mDisplayContent.mWmService.mTransactionFactory.get(),
+ updateMirroredSurface(mRecordedWindowContainer.getSyncTransaction(),
recordedContentBounds, surfaceSize);
} else {
// If the surface removed, do nothing. We will handle this via onDisplayChanged
@@ -325,6 +325,7 @@
.reparent(mDisplayContent.getOverlayLayer(), null);
// Retrieve the size of the DisplayArea to mirror.
updateMirroredSurface(transaction, mRecordedWindowContainer.getBounds(), surfaceSize);
+ transaction.apply();
// Notify the client about the visibility of the mirrored region, now that we have begun
// capture.
@@ -481,8 +482,7 @@
.setMatrix(mRecordedSurface, scale, 0 /* dtdx */, 0 /* dtdy */, scale)
// Position needs to be updated when the mirrored DisplayArea has changed, since
// the content will no longer be centered in the output surface.
- .setPosition(mRecordedSurface, shiftedX /* x */, shiftedY /* y */)
- .apply();
+ .setPosition(mRecordedSurface, shiftedX /* x */, shiftedY /* y */);
mLastRecordedBounds = new Rect(recordedContentBounds);
// Request to notify the client about the resize.
mMediaProjectionManager.notifyActiveProjectionCapturedContentResized(
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 2b6b62e..4180cd2 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -39,10 +39,11 @@
TAG_WITH_CLASS_NAME ? "DesktopModeLaunchParamsModifier" : TAG_ATM;
private static final boolean DEBUG = false;
- // Desktop mode feature flag.
- static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode", false) || SystemProperties.getBoolean(
- "persist.wm.debug.desktop_mode_2", false);
+ // Desktop mode feature flags.
+ private static final boolean DESKTOP_MODE_PROTO1_SUPPORTED =
+ SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false);
+ private static final boolean DESKTOP_MODE_PROTO2_SUPPORTED =
+ SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
// Override default freeform task width when desktop mode is enabled. In dips.
private static final int DESKTOP_MODE_DEFAULT_WIDTH_DP = SystemProperties.getInt(
"persist.wm.debug.desktop_mode.default_width", 840);
@@ -76,22 +77,37 @@
appendLog("task null, skipping");
return RESULT_SKIP;
}
- if (phase != PHASE_BOUNDS) {
- appendLog("not in bounds phase, skipping");
- return RESULT_SKIP;
- }
if (!task.isActivityTypeStandardOrUndefined()) {
appendLog("not standard or undefined activity type, skipping");
return RESULT_SKIP;
}
- if (!currentParams.mBounds.isEmpty()) {
- appendLog("currentParams has bounds set, not overriding");
+ if (phase < PHASE_WINDOWING_MODE) {
+ appendLog("not in windowing mode or bounds phase, skipping");
return RESULT_SKIP;
}
// Copy over any values
outParams.set(currentParams);
+ // In Proto2, trampoline task launches of an existing background task can result in the
+ // previous windowing mode to be restored even if the desktop mode state has changed.
+ // Let task launches inherit the windowing mode from the source task if available, which
+ // should have the desired windowing mode set by WM Shell. See b/286929122.
+ if (DESKTOP_MODE_PROTO2_SUPPORTED && source != null && source.getTask() != null) {
+ final Task sourceTask = source.getTask();
+ outParams.mWindowingMode = sourceTask.getWindowingMode();
+ appendLog("inherit-from-source=" + outParams.mWindowingMode);
+ }
+
+ if (phase == PHASE_WINDOWING_MODE) {
+ return RESULT_DONE;
+ }
+
+ if (!currentParams.mBounds.isEmpty()) {
+ appendLog("currentParams has bounds set, not overriding");
+ return RESULT_SKIP;
+ }
+
// Update width and height with default desktop mode values
float density = (float) task.getConfiguration().densityDpi / DENSITY_DEFAULT;
final int width = (int) (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f);
@@ -123,4 +139,9 @@
private void outputLog() {
if (DEBUG) Slog.d(TAG, mLogBuilder.toString());
}
+
+ /** Whether desktop mode is supported. */
+ static boolean isDesktopModeSupported() {
+ return DESKTOP_MODE_PROTO1_SUPPORTED || DESKTOP_MODE_PROTO2_SUPPORTED;
+ }
}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index e74e5787..91bb8d0 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -64,7 +64,7 @@
void registerDefaultModifiers(ActivityTaskSupervisor supervisor) {
// {@link TaskLaunchParamsModifier} handles window layout preferences.
registerModifier(new TaskLaunchParamsModifier(supervisor));
- if (DesktopModeLaunchParamsModifier.DESKTOP_MODE_SUPPORTED) {
+ if (DesktopModeLaunchParamsModifier.isDesktopModeSupported()) {
// {@link DesktopModeLaunchParamsModifier} handles default task size changes
registerModifier(new DesktopModeLaunchParamsModifier());
}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index bf511adf0..2394da9 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -433,7 +433,7 @@
final byte[] data = saveParamsToXml();
final File launchParamFolder = getLaunchParamFolder(mUserId);
- if (!launchParamFolder.isDirectory() && !launchParamFolder.mkdirs()) {
+ if (!launchParamFolder.isDirectory() && !launchParamFolder.mkdir()) {
Slog.w(TAG, "Failed to create folder for " + mUserId);
return;
}
diff --git a/services/core/java/com/android/server/wm/LetterboxConfiguration.java b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
index fda22ca..7a201a7 100644
--- a/services/core/java/com/android/server/wm/LetterboxConfiguration.java
+++ b/services/core/java/com/android/server/wm/LetterboxConfiguration.java
@@ -85,6 +85,13 @@
// TODO(b/288142656): Enable user aspect ratio settings by default.
private static final boolean DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS = false;
+ // Whether the letterbox wallpaper style is enabled by default
+ private static final String KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER =
+ "enable_letterbox_background_wallpaper";
+
+ // TODO(b/290048978): Enable wallpaper as default letterbox background.
+ private static final boolean DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER = false;
+
/**
* Override of aspect ratio for fixed orientation letterboxing that is set via ADB with
* set-fixed-orientation-letterbox-aspect-ratio or via {@link
@@ -101,9 +108,16 @@
/** Enum for Letterbox background type. */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({LETTERBOX_BACKGROUND_SOLID_COLOR, LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND,
- LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING, LETTERBOX_BACKGROUND_WALLPAPER})
+ @IntDef({LETTERBOX_BACKGROUND_OVERRIDE_UNSET,
+ LETTERBOX_BACKGROUND_SOLID_COLOR,
+ LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND,
+ LETTERBOX_BACKGROUND_APP_COLOR_BACKGROUND_FLOATING,
+ LETTERBOX_BACKGROUND_WALLPAPER})
@interface LetterboxBackgroundType {};
+
+ /** No letterbox background style set. Using the one defined by DeviceConfig. */
+ static final int LETTERBOX_BACKGROUND_OVERRIDE_UNSET = -1;
+
/** Solid background using color specified in R.color.config_letterboxBackgroundColor. */
static final int LETTERBOX_BACKGROUND_SOLID_COLOR = 0;
@@ -183,14 +197,14 @@
@Nullable private Integer mLetterboxBackgroundColorResourceIdOverride;
@LetterboxBackgroundType
- private int mLetterboxBackgroundType;
+ private final int mLetterboxBackgroundType;
- // Blur radius for LETTERBOX_BACKGROUND_WALLPAPER option in mLetterboxBackgroundType.
+ // Blur radius for LETTERBOX_BACKGROUND_WALLPAPER option from getLetterboxBackgroundType().
// Values <= 0 are ignored and 0 is used instead.
- private int mLetterboxBackgroundWallpaperBlurRadius;
+ private int mLetterboxBackgroundWallpaperBlurRadiusPx;
// Alpha of a black scrim shown over wallpaper letterbox background when
- // LETTERBOX_BACKGROUND_WALLPAPER option is selected for mLetterboxBackgroundType.
+ // LETTERBOX_BACKGROUND_WALLPAPER option is returned from getLetterboxBackgroundType().
// Values < 0 or >= 1 are ignored and 0.0 (transparent) is used instead.
private float mLetterboxBackgroundWallpaperDarkScrimAlpha;
@@ -252,6 +266,11 @@
// Allows to enable user aspect ratio settings ignoring flags.
private boolean mUserAppAspectRatioSettingsOverrideEnabled;
+ // The override for letterbox background type in case it's different from
+ // LETTERBOX_BACKGROUND_OVERRIDE_UNSET
+ @LetterboxBackgroundType
+ private int mLetterboxBackgroundTypeOverride = LETTERBOX_BACKGROUND_OVERRIDE_UNSET;
+
// Whether we should use split screen aspect ratio for the activity when camera compat treatment
// is enabled and activity is connected to the camera in fullscreen.
private final boolean mIsCameraCompatSplitScreenAspectRatioEnabled;
@@ -294,10 +313,10 @@
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
R.dimen.config_fixedOrientationLetterboxAspectRatio);
+ mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
mLetterboxActivityCornersRadius = mContext.getResources().getInteger(
R.integer.config_letterboxActivityCornersRadius);
- mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
- mLetterboxBackgroundWallpaperBlurRadius = mContext.getResources().getDimensionPixelSize(
+ mLetterboxBackgroundWallpaperBlurRadiusPx = mContext.getResources().getDimensionPixelSize(
R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
mLetterboxBackgroundWallpaperDarkScrimAlpha = mContext.getResources().getFloat(
R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha);
@@ -359,6 +378,8 @@
DEFAULT_VALUE_ENABLE_USER_ASPECT_RATIO_SETTINGS,
mContext.getResources().getBoolean(
R.bool.config_appCompatUserAppAspectRatioSettingsIsEnabled))
+ .addDeviceConfigEntry(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER,
+ DEFAULT_VALUE_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER, /* enabled */ true)
.build();
}
@@ -497,25 +518,39 @@
}
/**
- * Gets {@link LetterboxBackgroundType} specified in {@link
- * com.android.internal.R.integer.config_letterboxBackgroundType} or over via ADB command.
+ * Gets {@link LetterboxBackgroundType} specified via ADB command or the default one.
*/
@LetterboxBackgroundType
int getLetterboxBackgroundType() {
- return mLetterboxBackgroundType;
+ return mLetterboxBackgroundTypeOverride != LETTERBOX_BACKGROUND_OVERRIDE_UNSET
+ ? mLetterboxBackgroundTypeOverride
+ : getDefaultLetterboxBackgroundType();
}
- /** Sets letterbox background type. */
- void setLetterboxBackgroundType(@LetterboxBackgroundType int backgroundType) {
- mLetterboxBackgroundType = backgroundType;
+ /** Overrides the letterbox background type. */
+ void setLetterboxBackgroundTypeOverride(@LetterboxBackgroundType int backgroundType) {
+ mLetterboxBackgroundTypeOverride = backgroundType;
}
/**
- * Resets cletterbox background type to {@link
- * com.android.internal.R.integer.config_letterboxBackgroundType}.
+ * Resets letterbox background type value depending on the
+ * {@link #KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER} built time and runtime flags.
+ *
+ * <p>If enabled, the letterbox background type value is set toZ
+ * {@link #LETTERBOX_BACKGROUND_WALLPAPER}. When disabled the letterbox background type value
+ * comes from {@link R.integer.config_letterboxBackgroundType}.
*/
void resetLetterboxBackgroundType() {
- mLetterboxBackgroundType = readLetterboxBackgroundTypeFromConfig(mContext);
+ mLetterboxBackgroundTypeOverride = LETTERBOX_BACKGROUND_OVERRIDE_UNSET;
+ }
+
+ // Returns KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER if the DeviceConfig flag is enabled
+ // or the value in com.android.internal.R.integer.config_letterboxBackgroundType if the flag
+ // is disabled.
+ @LetterboxBackgroundType
+ private int getDefaultLetterboxBackgroundType() {
+ return mDeviceConfig.getFlagValue(KEY_ENABLE_LETTERBOX_BACKGROUND_WALLPAPER)
+ ? LETTERBOX_BACKGROUND_WALLPAPER : mLetterboxBackgroundType;
}
/** Returns a string representing the given {@link LetterboxBackgroundType}. */
@@ -548,7 +583,7 @@
/**
* Overrides alpha of a black scrim shown over wallpaper for {@link
- * #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link mLetterboxBackgroundType}.
+ * #LETTERBOX_BACKGROUND_WALLPAPER} option returned from {@link getLetterboxBackgroundType()}.
*
* <p>If given value is < 0 or >= 1, both it and a value of {@link
* com.android.internal.R.dimen.config_letterboxBackgroundWallaperDarkScrimAlpha} are ignored
@@ -575,33 +610,33 @@
}
/**
- * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in
- * {@link mLetterboxBackgroundType}.
+ * Overrides blur radius for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option from
+ * {@link getLetterboxBackgroundType()}.
*
* <p> If given value <= 0, both it and a value of {@link
* com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius} are ignored
* and 0 is used instead.
*/
- void setLetterboxBackgroundWallpaperBlurRadius(int radius) {
- mLetterboxBackgroundWallpaperBlurRadius = radius;
+ void setLetterboxBackgroundWallpaperBlurRadiusPx(int radius) {
+ mLetterboxBackgroundWallpaperBlurRadiusPx = radius;
}
/**
- * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
- * mLetterboxBackgroundType} to {@link
+ * Resets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option returned by {@link
+ * getLetterboxBackgroundType()} to {@link
* com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius}.
*/
- void resetLetterboxBackgroundWallpaperBlurRadius() {
- mLetterboxBackgroundWallpaperBlurRadius = mContext.getResources().getDimensionPixelSize(
+ void resetLetterboxBackgroundWallpaperBlurRadiusPx() {
+ mLetterboxBackgroundWallpaperBlurRadiusPx = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_letterboxBackgroundWallpaperBlurRadius);
}
/**
- * Gets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option in {@link
- * mLetterboxBackgroundType}.
+ * Gets blur raidus for {@link #LETTERBOX_BACKGROUND_WALLPAPER} option returned by {@link
+ * getLetterboxBackgroundType()}.
*/
- int getLetterboxBackgroundWallpaperBlurRadius() {
- return mLetterboxBackgroundWallpaperBlurRadius;
+ int getLetterboxBackgroundWallpaperBlurRadiusPx() {
+ return mLetterboxBackgroundWallpaperBlurRadiusPx;
}
/*
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index a816838..39f7570 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -894,7 +894,7 @@
this::shouldLetterboxHaveRoundedCorners,
this::getLetterboxBackgroundColor,
this::hasWallpaperBackgroundForLetterbox,
- this::getLetterboxWallpaperBlurRadius,
+ this::getLetterboxWallpaperBlurRadiusPx,
this::getLetterboxWallpaperDarkScrimAlpha,
this::handleHorizontalDoubleTap,
this::handleVerticalDoubleTap,
@@ -1315,7 +1315,7 @@
case LETTERBOX_BACKGROUND_WALLPAPER:
if (hasWallpaperBackgroundForLetterbox()) {
// Color is used for translucent scrim that dims wallpaper.
- return Color.valueOf(Color.BLACK);
+ return mLetterboxConfiguration.getLetterboxBackgroundColor();
}
Slog.w(TAG, "Wallpaper option is selected for letterbox background but "
+ "blur is not supported by a device or not supported in the current "
@@ -1472,10 +1472,10 @@
// Don't use wallpaper as a background if letterboxed for display cutout.
&& isLetterboxedNotForDisplayCutout(mainWindow)
// Check that dark scrim alpha or blur radius are provided
- && (getLetterboxWallpaperBlurRadius() > 0
+ && (getLetterboxWallpaperBlurRadiusPx() > 0
|| getLetterboxWallpaperDarkScrimAlpha() > 0)
// Check that blur is supported by a device if blur radius is provided.
- && (getLetterboxWallpaperBlurRadius() <= 0
+ && (getLetterboxWallpaperBlurRadiusPx() <= 0
|| isLetterboxWallpaperBlurSupported());
if (mShowWallpaperForLetterboxBackground != wallpaperShouldBeShown) {
mShowWallpaperForLetterboxBackground = wallpaperShouldBeShown;
@@ -1483,9 +1483,9 @@
}
}
- private int getLetterboxWallpaperBlurRadius() {
- int blurRadius = mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadius();
- return blurRadius < 0 ? 0 : blurRadius;
+ private int getLetterboxWallpaperBlurRadiusPx() {
+ int blurRadius = mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadiusPx();
+ return Math.max(blurRadius, 0);
}
private float getLetterboxWallpaperDarkScrimAlpha() {
@@ -1535,7 +1535,7 @@
pw.println(prefix + " letterboxBackgroundWallpaperDarkScrimAlpha="
+ getLetterboxWallpaperDarkScrimAlpha());
pw.println(prefix + " letterboxBackgroundWallpaperBlurRadius="
- + getLetterboxWallpaperBlurRadius());
+ + getLetterboxWallpaperBlurRadiusPx());
}
pw.println(prefix + " isHorizontalReachabilityEnabled="
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 7e0e5a4..5ec0119 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -509,7 +509,7 @@
private static boolean createParentDirectory(String filePath) {
File parentDir = new File(filePath).getParentFile();
- return parentDir.exists() || parentDir.mkdirs();
+ return parentDir.isDirectory() || parentDir.mkdir();
}
private static class TaskWriteQueueItem implements PersisterQueue.WriteQueueItem {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 3536ef9..0248acc 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -619,6 +619,12 @@
if (!isInTransientHide(wc)) {
mSyncEngine.addToSyncSet(mSyncId, wc);
}
+ if (wc.asWindowToken() != null && wc.asWindowToken().mRoundedCornerOverlay) {
+ // Only need to sync the transaction (SyncSet) without ChangeInfo because cutout and
+ // rounded corner overlay never need animations. Especially their surfaces may be put
+ // in root (null, see WindowToken#makeSurface()) that cannot reparent.
+ return;
+ }
ChangeInfo info = mChanges.get(wc);
if (info == null) {
info = new ChangeInfo(wc);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 4bc4c26..457a555 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -81,7 +81,9 @@
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.Trace;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Pools;
@@ -174,6 +176,9 @@
*/
protected SparseArray<InsetsSourceProvider> mInsetsSourceProviders = null;
+ @Nullable
+ private ArrayMap<IBinder, DeathRecipient> mInsetsOwnerDeathRecipientMap;
+
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final WindowList<E> mChildren = new WindowList<E>();
@@ -419,11 +424,12 @@
* Adds an {@link InsetsFrameProvider} which describes what insets should be provided to
* this {@link WindowContainer} and its children.
*
- * @param provider describes the insets types and the frames.
+ * @param provider describes the insets type and the frame.
+ * @param owner owns the insets source which only exists when the owner is alive.
*/
- void addLocalInsetsFrameProvider(InsetsFrameProvider provider) {
- if (provider == null) {
- throw new IllegalArgumentException("Insets type not specified.");
+ void addLocalInsetsFrameProvider(InsetsFrameProvider provider, IBinder owner) {
+ if (provider == null || owner == null) {
+ throw new IllegalArgumentException("Insets provider or owner not specified.");
}
if (mDisplayContent == null) {
// This is possible this container is detached when WM shell is responding to a previous
@@ -432,10 +438,26 @@
Slog.w(TAG, "Can't add insets frame provider when detached. " + this);
return;
}
+
+ if (mInsetsOwnerDeathRecipientMap == null) {
+ mInsetsOwnerDeathRecipientMap = new ArrayMap<>();
+ }
+ DeathRecipient deathRecipient = mInsetsOwnerDeathRecipientMap.get(owner);
+ if (deathRecipient == null) {
+ deathRecipient = new DeathRecipient(owner);
+ try {
+ owner.linkToDeath(deathRecipient, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to add source for " + provider + " since the owner has died.");
+ return;
+ }
+ mInsetsOwnerDeathRecipientMap.put(owner, deathRecipient);
+ }
+ final int id = provider.getId();
+ deathRecipient.addSourceId(id);
if (mLocalInsetsSources == null) {
mLocalInsetsSources = new SparseArray<>();
}
- final int id = provider.getId();
if (mLocalInsetsSources.get(id) != null) {
if (DEBUG) {
Slog.d(TAG, "The local insets source for this " + provider
@@ -448,27 +470,77 @@
mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
}
- void removeLocalInsetsFrameProvider(InsetsFrameProvider provider) {
- if (provider == null) {
- throw new IllegalArgumentException("Insets type not specified.");
- }
- if (mLocalInsetsSources == null) {
- return;
+ private class DeathRecipient implements IBinder.DeathRecipient {
+
+ private final IBinder mOwner;
+ private final ArraySet<Integer> mSourceIds = new ArraySet<>();
+
+ DeathRecipient(IBinder owner) {
+ mOwner = owner;
}
- final int id = provider.getId();
- if (mLocalInsetsSources.get(id) == null) {
- if (DEBUG) {
- Slog.d(TAG, "Given " + provider + " doesn't have a local insets source.");
+ void addSourceId(int id) {
+ mSourceIds.add(id);
+ }
+
+ void removeSourceId(int id) {
+ mSourceIds.remove(id);
+ }
+
+ boolean hasSource() {
+ return !mSourceIds.isEmpty();
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mWmService.mGlobalLock) {
+ boolean changed = false;
+ for (int i = mSourceIds.size() - 1; i >= 0; i--) {
+ changed |= removeLocalInsetsSource(mSourceIds.valueAt(i));
+ }
+ mSourceIds.clear();
+ mOwner.unlinkToDeath(this, 0);
+ mInsetsOwnerDeathRecipientMap.remove(mOwner);
+ if (changed && mDisplayContent != null) {
+ mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
+ }
}
- return;
}
- mLocalInsetsSources.remove(id);
+ }
- // Update insets if this window is attached.
- if (mDisplayContent != null) {
+ void removeLocalInsetsFrameProvider(InsetsFrameProvider provider, IBinder owner) {
+ if (provider == null || owner == null) {
+ throw new IllegalArgumentException("Insets provider or owner not specified.");
+ }
+ final int id = provider.getId();
+ if (removeLocalInsetsSource(id) && mDisplayContent != null) {
mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
}
+ if (mInsetsOwnerDeathRecipientMap == null) {
+ return;
+ }
+ final DeathRecipient deathRecipient = mInsetsOwnerDeathRecipientMap.get(owner);
+ if (deathRecipient == null) {
+ return;
+ }
+ deathRecipient.removeSourceId(id);
+ if (!deathRecipient.hasSource()) {
+ owner.unlinkToDeath(deathRecipient, 0);
+ mInsetsOwnerDeathRecipientMap.remove(owner);
+ }
+ }
+
+ private boolean removeLocalInsetsSource(int id) {
+ if (mLocalInsetsSources == null) {
+ return false;
+ }
+ if (mLocalInsetsSources.removeReturnOld(id) == null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Given id " + Integer.toHexString(id) + " doesn't exist.");
+ }
+ return false;
+ }
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 05e858d..f4781f9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -41,6 +41,7 @@
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Pair;
+import android.util.TypedValue;
import android.view.Display;
import android.view.IWindow;
import android.view.IWindowManager;
@@ -728,7 +729,7 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mLetterboxConfiguration.setLetterboxBackgroundType(backgroundType);
+ mLetterboxConfiguration.setLetterboxBackgroundTypeOverride(backgroundType);
}
return 0;
}
@@ -770,10 +771,10 @@
private int runSetLetterboxBackgroundWallpaperBlurRadius(PrintWriter pw)
throws RemoteException {
- final int radius;
+ final int radiusDp;
try {
String arg = getNextArgRequired();
- radius = Integer.parseInt(arg);
+ radiusDp = Integer.parseInt(arg);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: blur radius format " + e);
return -1;
@@ -783,7 +784,9 @@
return -1;
}
synchronized (mInternal.mGlobalLock) {
- mLetterboxConfiguration.setLetterboxBackgroundWallpaperBlurRadius(radius);
+ final int radiusPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ radiusDp, mInternal.mContext.getResources().getDisplayMetrics());
+ mLetterboxConfiguration.setLetterboxBackgroundWallpaperBlurRadiusPx(radiusPx);
}
return 0;
}
@@ -1050,7 +1053,7 @@
mLetterboxConfiguration.resetLetterboxBackgroundColor();
break;
case "wallpaperBlurRadius":
- mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadiusPx();
break;
case "wallpaperDarkScrimAlpha":
mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
@@ -1188,7 +1191,7 @@
mLetterboxConfiguration.resetLetterboxActivityCornersRadius();
mLetterboxConfiguration.resetLetterboxBackgroundType();
mLetterboxConfiguration.resetLetterboxBackgroundColor();
- mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadius();
+ mLetterboxConfiguration.resetLetterboxBackgroundWallpaperBlurRadiusPx();
mLetterboxConfiguration.resetLetterboxBackgroundWallpaperDarkScrimAlpha();
mLetterboxConfiguration.resetLetterboxHorizontalPositionMultiplier();
mLetterboxConfiguration.resetIsHorizontalReachabilityEnabled();
@@ -1262,7 +1265,7 @@
pw.println(" Background color: " + Integer.toHexString(
mLetterboxConfiguration.getLetterboxBackgroundColor().toArgb()));
pw.println(" Wallpaper blur radius: "
- + mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadius());
+ + mLetterboxConfiguration.getLetterboxBackgroundWallpaperBlurRadiusPx());
pw.println(" Wallpaper dark scrim alpha: "
+ mLetterboxConfiguration.getLetterboxBackgroundWallpaperDarkScrimAlpha());
pw.println("Is letterboxing for translucent activities enabled: "
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 32d574a..82adccd 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1090,7 +1090,8 @@
+ container);
break;
}
- container.addLocalInsetsFrameProvider(hop.getInsetsFrameProvider());
+ container.addLocalInsetsFrameProvider(
+ hop.getInsetsFrameProvider(), hop.getInsetsFrameOwner());
break;
}
case HIERARCHY_OP_TYPE_REMOVE_INSETS_FRAME_PROVIDER: {
@@ -1100,7 +1101,8 @@
+ container);
break;
}
- container.removeLocalInsetsFrameProvider(hop.getInsetsFrameProvider());
+ container.removeLocalInsetsFrameProvider(
+ hop.getInsetsFrameProvider(), hop.getInsetsFrameOwner());
break;
}
case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: {
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 0488247..4343edd 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -333,7 +333,10 @@
return -1;
}
static int getAnonPageAdvice(const Vma& vma) {
- if (vma.inode == 0 && !vma.is_shared) {
+ bool hasReadFlag = (vma.flags & PROT_READ) > 0;
+ bool hasWriteFlag = (vma.flags & PROT_WRITE) > 0;
+ bool hasExecuteFlag = (vma.flags & PROT_EXEC) > 0;
+ if ((hasReadFlag || hasWriteFlag) && !hasExecuteFlag && !vma.is_shared) {
return MADV_PAGEOUT;
}
return -1;
@@ -376,6 +379,9 @@
++coldVmaIndex;
break;
case MADV_PAGEOUT:
+#ifdef DEBUG_COMPACTION
+ ALOGE("Adding to compact vma=%s", vma.name.c_str());
+#endif
if (pageoutVmaIndex < pageoutVmas.size()) {
pageoutVmas[pageoutVmaIndex] = vma;
} else {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index c74c727..cb0b9c9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -968,7 +968,7 @@
void NativeInputManager::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
const std::set<gui::Uid>& uids) {
static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
- sysprop::InputProperties::enable_input_device_usage_metrics().value_or(false);
+ sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
if (!ENABLE_INPUT_DEVICE_USAGE_METRICS) return;
mInputManager->getMetricsCollector().notifyDeviceInteraction(deviceId, timestamp, uids);
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
index ce022e9..57b5d00 100644
--- a/services/core/xsd/display-layout-config/display-layout-config.xsd
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -53,6 +53,7 @@
<xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" />
+ <xs:element name="leadDisplayAddress" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="1" />
</xs:sequence>
<xs:attribute name="enabled" type="xs:boolean" use="optional" />
<xs:attribute name="defaultDisplay" type="xs:boolean" use="optional" />
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
index 42a800d..2d4f7a4 100644
--- a/services/core/xsd/display-layout-config/schema/current.txt
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -6,6 +6,7 @@
method public java.math.BigInteger getAddress();
method public String getBrightnessThrottlingMapId();
method public String getDisplayGroup();
+ method public java.math.BigInteger getLeadDisplayAddress();
method public String getPosition();
method public String getRefreshRateThermalThrottlingMapId();
method public String getRefreshRateZoneId();
@@ -16,6 +17,7 @@
method public void setDefaultDisplay(boolean);
method public void setDisplayGroup(String);
method public void setEnabled(boolean);
+ method public void setLeadDisplayAddress(java.math.BigInteger);
method public void setPosition(String);
method public void setRefreshRateThermalThrottlingMapId(String);
method public void setRefreshRateZoneId(String);
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index a1199d9..6747cea 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -91,8 +91,6 @@
CredentialManagerService, CredentialManagerServiceImpl> {
private static final String TAG = "CredManSysService";
- private static final String DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API =
- "enable_credential_description_api";
private static final String PERMISSION_DENIED_ERROR = "permission_denied";
private static final String PERMISSION_DENIED_WRITE_SECURE_SETTINGS_ERROR =
"Caller is missing WRITE_SECURE_SETTINGS permission";
@@ -311,14 +309,7 @@
}
public static boolean isCredentialDescriptionApiEnabled() {
- final long origId = Binder.clearCallingIdentity();
- try {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API,
- false);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
+ return true;
}
@SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2f1d67d..7857b25 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5132,8 +5132,11 @@
boolean deviceWideOnly) {
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
- && (isSystemUid(caller) || hasCallingOrSelfPermission(
- permission.SET_INITIAL_LOCK)));
+ && (isSystemUid(caller)
+ // Accept any permission that ILockSettings#setLockCredential() accepts.
+ || hasCallingOrSelfPermission(permission.SET_INITIAL_LOCK)
+ || hasCallingOrSelfPermission(permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS)
+ || hasCallingOrSelfPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)));
return getPasswordMinimumMetricsUnchecked(userHandle, deviceWideOnly);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
index 06f11be..733b1d9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyVersionUpgrader.java
@@ -29,6 +29,7 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
import java.util.ArrayList;
import java.util.List;
@@ -307,6 +308,8 @@
String versionString = Files.readAllLines(
file.toPath(), Charset.defaultCharset()).get(0);
return Integer.parseInt(versionString);
+ } catch (NoSuchFileException e) {
+ return 0; // expected on first boot
} catch (IOException | NumberFormatException | IndexOutOfBoundsException e) {
Slog.e(LOG_TAG, "Error reading version", e);
return 0;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ec83876..2f2e1cb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2876,11 +2876,9 @@
mSystemServiceManager.startService(SAFETY_CENTER_SERVICE_CLASS);
t.traceEnd();
- if (!isTv) {
- t.traceBegin("AppSearchModule");
- mSystemServiceManager.startService(APPSEARCH_MODULE_LIFECYCLE_CLASS);
- t.traceEnd();
- }
+ t.traceBegin("AppSearchModule");
+ mSystemServiceManager.startService(APPSEARCH_MODULE_LIFECYCLE_CLASS);
+ t.traceEnd();
if (SystemProperties.getBoolean("ro.config.isolated_compilation_enabled", false)) {
t.traceBegin("IsolatedCompilationService");
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 4aba30a..f660b42 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -16,7 +16,9 @@
package com.android.server.midi;
+import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.content.BroadcastReceiver;
@@ -48,6 +50,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.EventLog;
import android.util.Log;
@@ -81,6 +84,11 @@
// 2. synchronized (mDeviceConnections)
//TODO Introduce a single lock object to lock the whole state and avoid the requirement above.
+// All users should be able to connect to USB and Bluetooth MIDI devices.
+// All users can create can install an app that provides, a Virtual MIDI Device Service.
+// Users can not open virtual MIDI devices created by other users.
+// getDevices() surfaces devices that can be opened by that user.
+// openDevice() rejects devices that are cannot be opened by that user.
public class MidiService extends IMidiManager.Stub {
public static class Lifecycle extends SystemService {
@@ -97,10 +105,21 @@
}
@Override
+ @RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS},
+ anyOf = {Manifest.permission.QUERY_USERS,
+ Manifest.permission.CREATE_USERS,
+ Manifest.permission.MANAGE_USERS})
+ public void onUserStarting(@NonNull TargetUser user) {
+ mMidiService.onStartOrUnlockUser(user, false /* matchDirectBootUnaware */);
+ }
+
+ @Override
+ @RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS},
+ anyOf = {Manifest.permission.QUERY_USERS,
+ Manifest.permission.CREATE_USERS,
+ Manifest.permission.MANAGE_USERS})
public void onUserUnlocking(@NonNull TargetUser user) {
- if (user.getUserIdentifier() == UserHandle.USER_SYSTEM) {
- mMidiService.onUnlockUser();
- }
+ mMidiService.onStartOrUnlockUser(user, true /* matchDirectBootUnaware */);
}
}
@@ -134,6 +153,7 @@
private int mNextDeviceId = 1;
private final PackageManager mPackageManager;
+ private final UserManager mUserManager;
private static final String MIDI_LEGACY_STRING = "MIDI 1.0";
private static final String MIDI_UNIVERSAL_STRING = "MIDI 2.0";
@@ -159,21 +179,24 @@
private final HashSet<ParcelUuid> mNonMidiUUIDs = new HashSet<ParcelUuid>();
// PackageMonitor for listening to package changes
+ // uid is the uid of the package so use getChangingUserId() to fetch the userId.
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
+ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
public void onPackageAdded(String packageName, int uid) {
- addPackageDeviceServers(packageName);
+ addPackageDeviceServers(packageName, getChangingUserId());
}
@Override
+ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
public void onPackageModified(String packageName) {
- removePackageDeviceServers(packageName);
- addPackageDeviceServers(packageName);
+ removePackageDeviceServers(packageName, getChangingUserId());
+ addPackageDeviceServers(packageName, getChangingUserId());
}
@Override
public void onPackageRemoved(String packageName, int uid) {
- removePackageDeviceServers(packageName);
+ removePackageDeviceServers(packageName, getChangingUserId());
}
};
@@ -202,6 +225,10 @@
return mUid;
}
+ private int getUserId() {
+ return UserHandle.getUserId(mUid);
+ }
+
public void addListener(IMidiDeviceListener listener) {
if (mListeners.size() >= MAX_LISTENERS_PER_CLIENT) {
throw new SecurityException(
@@ -219,8 +246,12 @@
}
}
- public void addDeviceConnection(Device device, IMidiDeviceOpenCallback callback) {
- Log.d(TAG, "addDeviceConnection() device:" + device);
+ @RequiresPermission(anyOf = {Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ Manifest.permission.INTERACT_ACROSS_PROFILES})
+ public void addDeviceConnection(Device device, IMidiDeviceOpenCallback callback,
+ int userId) {
+ Log.d(TAG, "addDeviceConnection() device:" + device + " userId:" + userId);
if (mDeviceConnections.size() >= MAX_CONNECTIONS_PER_CLIENT) {
Log.i(TAG, "too many MIDI connections for UID = " + mUid);
throw new SecurityException(
@@ -228,7 +259,7 @@
}
DeviceConnection connection = new DeviceConnection(device, this, callback);
mDeviceConnections.put(connection.getToken(), connection);
- device.addDeviceConnection(connection);
+ device.addDeviceConnection(connection, userId);
}
// called from MidiService.closeDevice()
@@ -251,8 +282,8 @@
}
public void deviceAdded(Device device) {
- // ignore private devices that our client cannot access
- if (!device.isUidAllowed(mUid)) return;
+ // ignore devices that our client cannot access
+ if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
try {
@@ -265,8 +296,8 @@
}
public void deviceRemoved(Device device) {
- // ignore private devices that our client cannot access
- if (!device.isUidAllowed(mUid)) return;
+ // ignore devices that our client cannot access
+ if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
MidiDeviceInfo deviceInfo = device.getDeviceInfo();
try {
@@ -279,8 +310,8 @@
}
public void deviceStatusChanged(Device device, MidiDeviceStatus status) {
- // ignore private devices that our client cannot access
- if (!device.isUidAllowed(mUid)) return;
+ // ignore devices that our client cannot access
+ if (!device.isUidAllowed(mUid) || !device.isUserIdAllowed(getUserId())) return;
try {
for (IMidiDeviceListener listener : mListeners.values()) {
@@ -354,6 +385,8 @@
private final ServiceInfo mServiceInfo;
// UID of device implementation
private final int mUid;
+ // User Id of the app. Only used for virtual devices
+ private final int mUserId;
// ServiceConnection for implementing Service (virtual devices only)
// mServiceConnection is non-null when connected or attempting to connect to the service
@@ -375,19 +408,24 @@
private AtomicInteger mTotalOutputBytes = new AtomicInteger();
public Device(IMidiDeviceServer server, MidiDeviceInfo deviceInfo,
- ServiceInfo serviceInfo, int uid) {
+ ServiceInfo serviceInfo, int uid, int userId) {
mDeviceInfo = deviceInfo;
mServiceInfo = serviceInfo;
mUid = uid;
+ mUserId = userId;
mBluetoothDevice = (BluetoothDevice)deviceInfo.getProperties().getParcelable(
MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE, android.bluetooth.BluetoothDevice.class);;
setDeviceServer(server);
}
+ @RequiresPermission(anyOf = {Manifest.permission.QUERY_USERS,
+ Manifest.permission.CREATE_USERS,
+ Manifest.permission.MANAGE_USERS})
public Device(BluetoothDevice bluetoothDevice) {
mBluetoothDevice = bluetoothDevice;
mServiceInfo = null;
mUid = mBluetoothServiceUid;
+ mUserId = mUserManager.getMainUser().getIdentifier();
}
private void setDeviceServer(IMidiDeviceServer server) {
@@ -468,11 +506,22 @@
return mUid;
}
+ public int getUserId() {
+ return mUserId;
+ }
+
public boolean isUidAllowed(int uid) {
return (!mDeviceInfo.isPrivate() || mUid == uid);
}
- public void addDeviceConnection(DeviceConnection connection) {
+ public boolean isUserIdAllowed(int userId) {
+ return (mDeviceInfo.getType() != MidiDeviceInfo.TYPE_VIRTUAL || mUserId == userId);
+ }
+
+ @RequiresPermission(anyOf = {Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ Manifest.permission.INTERACT_ACROSS_USERS,
+ Manifest.permission.INTERACT_ACROSS_PROFILES})
+ public void addDeviceConnection(DeviceConnection connection, int userId) {
Log.d(TAG, "addDeviceConnection() [A] connection:" + connection);
synchronized (mDeviceConnections) {
mDeviceConnectionsAdded.incrementAndGet();
@@ -537,8 +586,8 @@
new ComponentName(mServiceInfo.packageName, mServiceInfo.name));
}
- if (!mContext.bindService(intent, mServiceConnection,
- Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindServiceAsUser(intent, mServiceConnection,
+ Context.BIND_AUTO_CREATE, UserHandle.of(mUserId))) {
Log.e(TAG, "Unable to bind service: " + intent);
setDeviceServer(null);
mServiceConnection = null;
@@ -886,6 +935,8 @@
public MidiService(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
+ mUserManager = mContext.getSystemService(UserManager.class);
+ mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
// TEMPORARY - Disable BTL-MIDI
//FIXME - b/25689266
@@ -913,32 +964,41 @@
// mNonMidiUUIDs.add(BluetoothUuid.BATTERY);
}
- private void onUnlockUser() {
- mPackageMonitor.register(mContext, null, true);
-
+ @RequiresPermission(allOf = {Manifest.permission.INTERACT_ACROSS_USERS},
+ anyOf = {Manifest.permission.QUERY_USERS,
+ Manifest.permission.CREATE_USERS,
+ Manifest.permission.MANAGE_USERS})
+ private void onStartOrUnlockUser(TargetUser user, boolean matchDirectBootUnaware) {
+ Log.d(TAG, "onStartOrUnlockUser " + user.getUserIdentifier() + " matchDirectBootUnaware: "
+ + matchDirectBootUnaware);
Intent intent = new Intent(MidiDeviceService.SERVICE_INTERFACE);
- List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServices(intent,
- PackageManager.GET_META_DATA);
+ int resolveFlags = PackageManager.GET_META_DATA;
+ if (matchDirectBootUnaware) {
+ resolveFlags |= PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ }
+ List<ResolveInfo> resolveInfos = mPackageManager.queryIntentServicesAsUser(intent,
+ resolveFlags, user.getUserIdentifier());
if (resolveInfos != null) {
int count = resolveInfos.size();
for (int i = 0; i < count; i++) {
ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
if (serviceInfo != null) {
- addPackageDeviceServer(serviceInfo);
+ addPackageDeviceServer(serviceInfo, user.getUserIdentifier());
}
}
}
- PackageInfo info;
- try {
- info = mPackageManager.getPackageInfo(MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE, 0);
- } catch (PackageManager.NameNotFoundException e) {
- info = null;
- }
- if (info != null && info.applicationInfo != null) {
- mBluetoothServiceUid = info.applicationInfo.uid;
- } else {
- mBluetoothServiceUid = -1;
+ if (user.getUserIdentifier() == mUserManager.getMainUser().getIdentifier()) {
+ PackageInfo info;
+ try {
+ info = mPackageManager.getPackageInfoAsUser(
+ MidiManager.BLUETOOTH_MIDI_SERVICE_PACKAGE, 0, user.getUserIdentifier());
+ } catch (PackageManager.NameNotFoundException e) {
+ info = null;
+ }
+ if (info != null && info.applicationInfo != null) {
+ mBluetoothServiceUid = info.applicationInfo.uid;
+ }
}
}
@@ -960,10 +1020,11 @@
// Inform listener of the status of all known devices.
private void updateStickyDeviceStatus(int uid, IMidiDeviceListener listener) {
+ int userId = UserHandle.getUserId(uid);
synchronized (mDevicesByInfo) {
for (Device device : mDevicesByInfo.values()) {
- // ignore private devices that our client cannot access
- if (device.isUidAllowed(uid)) {
+ // ignore devices that our client cannot access
+ if (device.isUidAllowed(uid) && device.isUserIdAllowed(userId)) {
try {
MidiDeviceStatus status = device.getDeviceStatus();
if (status != null) {
@@ -989,10 +1050,11 @@
public MidiDeviceInfo[] getDevicesForTransport(int transport) {
ArrayList<MidiDeviceInfo> deviceInfos = new ArrayList<MidiDeviceInfo>();
int uid = Binder.getCallingUid();
+ int userId = getCallingUserId();
synchronized (mDevicesByInfo) {
for (Device device : mDevicesByInfo.values()) {
- if (device.isUidAllowed(uid)) {
+ if (device.isUidAllowed(uid) && device.isUserIdAllowed(userId)) {
// UMP devices have protocols that are not PROTOCOL_UNKNOWN
if (transport == MidiManager.TRANSPORT_UNIVERSAL_MIDI_PACKETS) {
if (device.getDeviceInfo().getDefaultProtocol()
@@ -1029,6 +1091,9 @@
if (!device.isUidAllowed(Binder.getCallingUid())) {
throw new SecurityException("Attempt to open private device with wrong UID");
}
+ if (!device.isUserIdAllowed(getCallingUserId())) {
+ throw new SecurityException("Attempt to open virtual device with wrong user id");
+ }
}
if (deviceInfo.getType() == MidiDeviceInfo.TYPE_USB) {
@@ -1044,7 +1109,7 @@
final long identity = Binder.clearCallingIdentity();
try {
Log.i(TAG, "addDeviceConnection() [B] device:" + device);
- client.addDeviceConnection(device, callback);
+ client.addDeviceConnection(device, callback, getCallingUserId());
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1106,7 +1171,7 @@
final long identity = Binder.clearCallingIdentity();
try {
Log.i(TAG, "addDeviceConnection() [C] device:" + device);
- client.addDeviceConnection(device, callback);
+ client.addDeviceConnection(device, callback, getCallingUserId());
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1124,6 +1189,7 @@
int numOutputPorts, String[] inputPortNames, String[] outputPortNames,
Bundle properties, int type, int defaultProtocol) {
int uid = Binder.getCallingUid();
+ int userId = getCallingUserId();
if (type == MidiDeviceInfo.TYPE_USB && uid != Process.SYSTEM_UID) {
throw new SecurityException("only system can create USB devices");
} else if (type == MidiDeviceInfo.TYPE_BLUETOOTH && uid != mBluetoothServiceUid) {
@@ -1133,7 +1199,7 @@
synchronized (mDevicesByInfo) {
return addDeviceLocked(type, numInputPorts, numOutputPorts, inputPortNames,
outputPortNames, properties, server, null, false, uid,
- defaultProtocol);
+ defaultProtocol, userId);
}
}
@@ -1210,7 +1276,8 @@
private MidiDeviceInfo addDeviceLocked(int type, int numInputPorts, int numOutputPorts,
String[] inputPortNames, String[] outputPortNames, Bundle properties,
IMidiDeviceServer server, ServiceInfo serviceInfo,
- boolean isPrivate, int uid, int defaultProtocol) {
+ boolean isPrivate, int uid, int defaultProtocol, int userId) {
+ Log.d(TAG, "addDeviceLocked()" + uid + " type:" + type);
// Limit the number of devices per app.
int deviceCountForApp = 0;
@@ -1250,7 +1317,7 @@
}
}
if (device == null) {
- device = new Device(server, deviceInfo, serviceInfo, uid);
+ device = new Device(server, deviceInfo, serviceInfo, uid, userId);
}
mDevicesByInfo.put(deviceInfo, device);
if (bluetoothDevice != null) {
@@ -1281,12 +1348,14 @@
}
}
- private void addPackageDeviceServers(String packageName) {
+ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+ private void addPackageDeviceServers(String packageName, int userId) {
PackageInfo info;
try {
- info = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+ info = mPackageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
return;
@@ -1295,13 +1364,14 @@
ServiceInfo[] services = info.services;
if (services == null) return;
for (int i = 0; i < services.length; i++) {
- addPackageDeviceServer(services[i]);
+ addPackageDeviceServer(services[i], userId);
}
}
private static final String[] EMPTY_STRING_ARRAY = new String[0];
- private void addPackageDeviceServer(ServiceInfo serviceInfo) {
+ private void addPackageDeviceServer(ServiceInfo serviceInfo, int userId) {
+ Log.d(TAG, "addPackageDeviceServer()" + userId);
XmlResourceParser parser = null;
try {
@@ -1404,8 +1474,8 @@
int uid;
try {
- ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
- serviceInfo.packageName, 0);
+ ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser(
+ serviceInfo.packageName, 0, userId);
uid = appInfo.uid;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "could not fetch ApplicationInfo for "
@@ -1419,7 +1489,7 @@
inputPortNames.toArray(EMPTY_STRING_ARRAY),
outputPortNames.toArray(EMPTY_STRING_ARRAY),
properties, null, serviceInfo, isPrivate, uid,
- MidiDeviceInfo.PROTOCOL_UNKNOWN);
+ MidiDeviceInfo.PROTOCOL_UNKNOWN, userId);
}
// setting properties to null signals that we are no longer
// processing a <device>
@@ -1437,12 +1507,13 @@
}
}
- private void removePackageDeviceServers(String packageName) {
+ private void removePackageDeviceServers(String packageName, int userId) {
synchronized (mDevicesByInfo) {
Iterator<Device> iterator = mDevicesByInfo.values().iterator();
while (iterator.hasNext()) {
Device device = iterator.next();
- if (packageName.equals(device.getPackageName())) {
+ if (packageName.equals(device.getPackageName())
+ && (device.getUserId() == userId)) {
iterator.remove();
removeDeviceLocked(device);
}
@@ -1571,4 +1642,11 @@
String extractUsbDeviceTag(String propertyName) {
return propertyName.substring(propertyName.length() - MIDI_LEGACY_STRING.length());
}
+
+ /**
+ * @return the user id of the calling user.
+ */
+ private int getCallingUserId() {
+ return UserHandle.getUserId(Binder.getCallingUid());
+ }
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index d39c8a0..aa86cd6 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -390,7 +390,14 @@
packageState: PackageState,
changedPermissionNames: MutableIndexedSet<String>
) {
- packageState.androidPackage!!.permissions.forEachIndexed { _, parsedPermission ->
+ val androidPackage = packageState.androidPackage!!
+ // This may not be the same package as the old permission because the old permission owner
+ // can be different, hence using this somewhat strange name to prevent misuse.
+ val oldNewPackage = oldState.externalState.packageStates[packageState.packageName]
+ ?.androidPackage
+ val isPackageSigningChanged = oldNewPackage != null &&
+ androidPackage.signingDetails != oldNewPackage.signingDetails
+ androidPackage.permissions.forEachIndexed { _, parsedPermission ->
val newPermissionInfo = PackageInfoUtils.generatePermissionInfo(
parsedPermission, PackageManager.GET_META_DATA.toLong()
)!!
@@ -520,7 +527,7 @@
newPackageName != oldPermission.packageName ||
newPermission.protectionLevel != oldPermission.protectionLevel || (
oldPermission.isReconciled && (
- (
+ (newPermission.isSignature && isPackageSigningChanged) || (
newPermission.isKnownSigner &&
newPermission.knownCerts != oldPermission.knownCerts
) || (
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index 1a8e00c..ffd7332 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.mockito.ArgumentMatchers.any;
@@ -125,6 +126,7 @@
protected InputMethodManagerService mInputMethodManagerService;
protected ServiceThread mServiceThread;
protected boolean mIsLargeScreen;
+ private InputManagerGlobal.TestSession mInputManagerGlobalSession;
@BeforeClass
public static void setupClass() {
@@ -145,8 +147,7 @@
.mockStatic(SystemServerInitThreadPool.class)
.startMocking();
- mContext = InstrumentationRegistry.getInstrumentation().getContext();
- spyOn(mContext);
+ mContext = spy(InstrumentationRegistry.getInstrumentation().getContext());
mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
mIsLargeScreen = mContext.getResources().getConfiguration()
@@ -186,7 +187,7 @@
// Injecting and mocked InputMethodBindingController and InputMethod.
mMockInputMethodInvoker = IInputMethodInvoker.create(mMockInputMethod);
- InputManagerGlobal.resetInstance(mMockIInputManager);
+ mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mMockIInputManager);
synchronized (ImfLock.class) {
when(mMockInputMethodBindingController.getCurMethod())
.thenReturn(mMockInputMethodInvoker);
@@ -262,6 +263,10 @@
if (mMockingSession != null) {
mMockingSession.finishMocking();
}
+
+ if (mInputManagerGlobalSession != null) {
+ mInputManagerGlobalSession.close();
+ }
LocalServices.removeServiceForTest(InputMethodManagerInternal.class);
}
diff --git a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6 b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
index 2da2436..c2418be 100644
--- a/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
+++ b/services/tests/PackageManagerServiceTests/server/res/raw/install_app1_cert5_rotated_cert6
Binary files differ
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java b/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
index 130e6ad..4b124ca 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
@@ -19,8 +19,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
-import android.view.Display;
import android.view.DisplayAddress;
import androidx.test.filters.SmallTest;
@@ -65,9 +65,15 @@
Layout testLayout = new Layout();
createDefaultDisplay(testLayout, 123456L);
- createNonDefaultDisplay(testLayout, 78910L, /* enabled= */ false, /* group= */ null);
- createNonDefaultDisplay(testLayout, 98765L, /* enabled= */ true, /* group= */ "group1");
- createNonDefaultDisplay(testLayout, 786L, /* enabled= */ false, /* group= */ "group2");
+ createNonDefaultDisplay(testLayout, 78910L, /* enabled= */ false, /* group= */ null,
+ /* leadDisplayAddress= */ null);
+ createNonDefaultDisplay(testLayout, 98765L, /* enabled= */ true, /* group= */ "group1",
+ /* leadDisplayAddress= */ null);
+ createNonDefaultDisplay(testLayout, 786L, /* enabled= */ false, /* group= */ "group2",
+ /* leadDisplayAddress= */ null);
+ createNonDefaultDisplay(testLayout, 1092L, /* enabled= */ true, /* group= */ null,
+ DisplayAddress.fromPhysicalDisplayId(78910L));
+ testLayout.postProcessLocked();
assertEquals(testLayout, configLayout);
}
@@ -78,7 +84,9 @@
Layout testLayout = new Layout();
createDefaultDisplay(testLayout, 78910L);
- createNonDefaultDisplay(testLayout, 123456L, /* enabled= */ false, /* group= */ null);
+ createNonDefaultDisplay(testLayout, 123456L, /* enabled= */ false, /* group= */ null,
+ /* leadDisplayAddress= */ null);
+ testLayout.postProcessLocked();
assertEquals(testLayout, configLayout);
}
@@ -122,20 +130,132 @@
Layout testLayout = new Layout();
testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(345L),
/* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
- mDisplayIdProducerMock, Layout.Display.POSITION_FRONT, Display.DEFAULT_DISPLAY,
- /* brightnessThrottlingMapId= */ "brightness1",
+ mDisplayIdProducerMock, Layout.Display.POSITION_FRONT,
+ /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ "brightness1",
/* refreshRateZoneId= */ "zone1",
/* refreshRateThermalThrottlingMapId= */ "rr1");
testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(678L),
/* isDefault= */ false, /* isEnabled= */ false, /* displayGroupName= */ "group1",
- mDisplayIdProducerMock, Layout.Display.POSITION_REAR, Display.DEFAULT_DISPLAY,
- /* brightnessThrottlingMapId= */ "brightness2",
+ mDisplayIdProducerMock, Layout.Display.POSITION_REAR,
+ /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ "brightness2",
/* refreshRateZoneId= */ "zone2",
/* refreshRateThermalThrottlingMapId= */ "rr2");
+ testLayout.postProcessLocked();
assertEquals(testLayout, configLayout);
}
+ @Test
+ public void testLeadDisplayAddress() {
+ Layout layout = new Layout();
+ createNonDefaultDisplay(layout, 111L, /* enabled= */ true, /* group= */ null,
+ /* leadDisplayAddress= */ null);
+ createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
+ DisplayAddress.fromPhysicalDisplayId(111L));
+
+ layout.postProcessLocked();
+
+ com.android.server.display.layout.Layout.Display display111 =
+ layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(111));
+ com.android.server.display.layout.Layout.Display display222 =
+ layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(222));
+ assertEquals(display111.getLeadDisplayId(), layout.NO_LEAD_DISPLAY);
+ assertEquals(display222.getLeadDisplayId(), display111.getLogicalDisplayId());
+ }
+
+ @Test
+ public void testLeadDisplayAddress_defaultDisplay() {
+ Layout layout = new Layout();
+ createDefaultDisplay(layout, 123456L);
+
+ layout.postProcessLocked();
+
+ com.android.server.display.layout.Layout.Display display =
+ layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(123456));
+ assertEquals(display.getLeadDisplayId(), layout.NO_LEAD_DISPLAY);
+ }
+
+ @Test
+ public void testLeadDisplayAddress_noLeadDisplay() {
+ Layout layout = new Layout();
+ createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
+ /* leadDisplayAddress= */ null);
+
+ layout.postProcessLocked();
+
+ com.android.server.display.layout.Layout.Display display =
+ layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(222));
+ assertEquals(display.getLeadDisplayId(), layout.NO_LEAD_DISPLAY);
+ }
+
+ @Test
+ public void testLeadDisplayAddress_selfLeadDisplayForNonDefaultDisplay() {
+ Layout layout = new Layout();
+
+ assertThrows("Expected Layout to throw IllegalArgumentException when the display points out"
+ + " itself as a lead display",
+ IllegalArgumentException.class,
+ () -> layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(123L),
+ /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
+ mDisplayIdProducerMock, Layout.Display.POSITION_FRONT,
+ DisplayAddress.fromPhysicalDisplayId(123L),
+ /* brightnessThrottlingMapId= */ null, /* refreshRateZoneId= */ null,
+ /* refreshRateThermalThrottlingMapId= */ null));
+ }
+
+ @Test
+ public void testLeadDisplayAddress_wrongLeadDisplayForDefaultDisplay() {
+ Layout layout = new Layout();
+
+ assertThrows("Expected Layout to throw IllegalArgumentException when the default display "
+ + "has a lead display",
+ IllegalArgumentException.class,
+ () -> layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(123L),
+ /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
+ mDisplayIdProducerMock, Layout.Display.POSITION_FRONT,
+ DisplayAddress.fromPhysicalDisplayId(987L),
+ /* brightnessThrottlingMapId= */ null, /* refreshRateZoneId= */ null,
+ /* refreshRateThermalThrottlingMapId= */ null));
+ }
+
+ @Test
+ public void testLeadDisplayAddress_notExistingLeadDisplayForNonDefaultDisplay() {
+ Layout layout = new Layout();
+ createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
+ DisplayAddress.fromPhysicalDisplayId(111L));
+
+ assertThrows("Expected Layout to throw IllegalArgumentException when a lead display doesn't"
+ + " exist", IllegalArgumentException.class, () -> layout.postProcessLocked());
+ }
+
+ @Test
+ public void testLeadDisplayAddress_leadDisplayInDifferentDisplayGroup() {
+ Layout layout = new Layout();
+ createNonDefaultDisplay(layout, 111, /* enabled= */ true, /* group= */ "group1",
+ /* leadDisplayAddress= */ null);
+ createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ "group2",
+ DisplayAddress.fromPhysicalDisplayId(111L));
+
+ assertThrows("Expected Layout to throw IllegalArgumentException when pointing to a lead "
+ + "display in the different group",
+ IllegalArgumentException.class, () -> layout.postProcessLocked());
+ }
+
+ @Test
+ public void testLeadDisplayAddress_cyclicLeadDisplay() {
+ Layout layout = new Layout();
+ createNonDefaultDisplay(layout, 111, /* enabled= */ true, /* group= */ null,
+ DisplayAddress.fromPhysicalDisplayId(222L));
+ createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
+ DisplayAddress.fromPhysicalDisplayId(333L));
+ createNonDefaultDisplay(layout, 333L, /* enabled= */ true, /* group= */ null,
+ DisplayAddress.fromPhysicalDisplayId(222L));
+
+ assertThrows("Expected Layout to throw IllegalArgumentException when pointing to a lead "
+ + "display in the different group",
+ IllegalArgumentException.class, () -> layout.postProcessLocked());
+ }
+
////////////////////
// Helper Methods //
////////////////////
@@ -145,10 +265,11 @@
mDisplayIdProducerMock);
}
- private void createNonDefaultDisplay(Layout layout, long id, boolean enabled, String group) {
+ private void createNonDefaultDisplay(Layout layout, long id, boolean enabled, String group,
+ DisplayAddress leadDisplayAddress) {
layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(id), /* isDefault= */ false,
enabled, group, mDisplayIdProducerMock, Layout.Display.POSITION_UNKNOWN,
- Display.DEFAULT_DISPLAY, /* brightnessThrottlingMapId= */ null,
+ leadDisplayAddress, /* brightnessThrottlingMapId= */ null,
/* refreshRateZoneId= */ null,
/* refreshRateThermalThrottlingMapId= */ null);
}
@@ -177,6 +298,10 @@
+ "<display enabled=\"false\" displayGroup=\"group2\">\n"
+ "<address>786</address>\n"
+ "</display>\n"
+ + "<display enabled=\"true\">\n"
+ + "<address>1092</address>\n"
+ + "<leadDisplayAddress>78910</leadDisplayAddress>\n"
+ + "</display>\n"
+ "</layout>\n"
+ "<layout>\n"
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 1eec70d..3e695c9 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -604,13 +604,13 @@
layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address,
/* isDefault= */ true, /* isEnabled= */ true, /* displayGroup= */ null,
mIdProducer, POSITION_UNKNOWN,
- /* leadDisplayId= */ Display.DEFAULT_DISPLAY,
+ /* leadDisplayAddress= */ null,
/* brightnessThrottlingMapId= */ "concurrent",
/* refreshRateZoneId= */ null, /* refreshRateThermalThrottlingMapId= */ null);
layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address,
/* isDefault= */ false, /* isEnabled= */ true, /* displayGroup= */ null,
mIdProducer, POSITION_UNKNOWN,
- /* leadDisplayId= */ Display.DEFAULT_DISPLAY,
+ /* leadDisplayAddress= */ null,
/* brightnessThrottlingMapId= */ "concurrent",
/* refreshRateZoneId= */ null, /* refreshRateThermalThrottlingMapId= */ null);
when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout);
@@ -646,7 +646,7 @@
assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
assertEquals(-1, mLogicalDisplayMapper.getDisplayLocked(device1)
.getLeadDisplayIdLocked());
- assertEquals(0, mLogicalDisplayMapper.getDisplayLocked(device2)
+ assertEquals(-1, mLogicalDisplayMapper.getDisplayLocked(device2)
.getLeadDisplayIdLocked());
assertEquals("concurrent", mLogicalDisplayMapper.getDisplayLocked(device1)
.getDisplayInfoLocked().thermalBrightnessThrottlingDataId);
@@ -811,7 +811,7 @@
mIdProducer);
layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address,
/* isDefault= */ false, /* isEnabled= */ true, /* displayGroupName= */ null,
- mIdProducer, POSITION_REAR, Display.DEFAULT_DISPLAY,
+ mIdProducer, POSITION_REAR, /* leadDisplayAddress= */ null,
/* brightnessThrottlingMapId= */ null, /* refreshRateZoneId= */ null,
/* refreshRateThermalThrottlingMapId= */null);
when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout);
@@ -861,7 +861,7 @@
private void createNonDefaultDisplay(Layout layout, DisplayAddress address, boolean enabled,
String group) {
layout.createDisplayLocked(address, /* isDefault= */ false, enabled, group, mIdProducer,
- Layout.Display.POSITION_UNKNOWN, Display.DEFAULT_DISPLAY,
+ Layout.Display.POSITION_UNKNOWN, /* leadDisplayAddress= */ null,
/* brightnessThrottlingMapId= */ null, /* refreshRateZoneId= */ null,
/* refreshRateThermalThrottlingMapId= */ null);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index ff04728..08f5d03 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -620,6 +620,28 @@
assertEquals(BroadcastProcessQueue.REASON_CORE_UID, queue.getRunnableAtReason());
}
+ @Test
+ public void testRunnableAt_freezableCoreUid() {
+ final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
+ "com.android.bluetooth", Process.BLUETOOTH_UID);
+
+ // Mark the process as freezable
+ queue.setProcessAndUidState(mProcess, false, true);
+ final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
+ final BroadcastOptions options = BroadcastOptions.makeWithDeferUntilActive(true);
+ final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick, options,
+ List.of(makeMockRegisteredReceiver()), false);
+ enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
+
+ assertEquals(Long.MAX_VALUE, queue.getRunnableAt());
+ assertEquals(BroadcastProcessQueue.REASON_CACHED_INFINITE_DEFER,
+ queue.getRunnableAtReason());
+
+ queue.setProcessAndUidState(mProcess, false, false);
+ assertThat(queue.getRunnableAt()).isEqualTo(timeTickRecord.enqueueTime);
+ assertEquals(BroadcastProcessQueue.REASON_CORE_UID, queue.getRunnableAtReason());
+ }
+
/**
* Verify that a cached process that would normally be delayed becomes
* immediately runnable when the given broadcast is enqueued.
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 22ad7c4..03439e55 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -969,7 +969,7 @@
mCachedAppOptimizerUnderTest.mLastCompactionStats.clear();
- if (CachedAppOptimizer.ENABLE_FILE_COMPACT) {
+ if (CachedAppOptimizer.ENABLE_SHARED_AND_CODE_COMPACT) {
// We force a some compaction
mCachedAppOptimizerUnderTest.compactApp(processRecord,
CachedAppOptimizer.CompactProfile.SOME, CachedAppOptimizer.CompactSource.APP,
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java
index 2c2b1f5..4c633a1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java
@@ -77,7 +77,8 @@
IRemoteCallback callback = createMockPackageMonitorCallback();
mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
- FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */);
+ FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
+ null /* instantUserIds */);
verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
}
@@ -88,14 +89,15 @@
mPackageMonitorCallbackHelper.registerPackageMonitorCallback(callback, 0 /* userId */);
mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
- FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0});
+ FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0}, null /* instantUserIds */);
verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(any());
reset(callback);
mPackageMonitorCallbackHelper.unregisterPackageMonitorCallback(callback);
mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
- FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */);
+ FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
+ null /* instantUserIds */);
verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
}
@@ -106,7 +108,8 @@
mPackageMonitorCallbackHelper.registerPackageMonitorCallback(callback, 0 /* userId */);
mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
- FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */);
+ FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
+ null /* instantUserIds */);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(
@@ -128,7 +131,8 @@
mPackageMonitorCallbackHelper.registerPackageMonitorCallback(callback, 0 /* userId */);
// Notify for user 10
mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
- FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{10} /* userIds */);
+ FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{10} /* userIds */,
+ null /* instantUserIds */);
verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
}
@@ -143,7 +147,7 @@
mPackageMonitorCallbackHelper.registerPackageMonitorCallback(callback, 0 /* userId */);
mPackageMonitorCallbackHelper.notifyPackageChanged(FAKE_PACKAGE_NAME,
false /* dontKillApp */, components, FAKE_PACKAGE_UID, null /* reason */,
- new int[]{0} /* userIds */);
+ new int[]{0} /* userIds */, null /* instantUserIds */);
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(
@@ -217,6 +221,19 @@
assertThat(pkgNames[0]).isEqualTo(FAKE_PACKAGE_NAME);
}
+ @Test
+ public void testPackageMonitorCallback_onUserRemoved_callbackNotCalled() throws Exception {
+ IRemoteCallback callback = createMockPackageMonitorCallback();
+ mPackageMonitorCallbackHelper.registerPackageMonitorCallback(callback, 10 /* userId */);
+
+ mPackageMonitorCallbackHelper.onUserRemoved(10);
+ mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
+ FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{10} /* userIds */,
+ null /* instantUserIds */);
+
+ verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
+ }
+
private IRemoteCallback createMockPackageMonitorCallback() {
return spy(new IRemoteCallback.Stub() {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 81dd961..d4c6fad 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -606,9 +606,10 @@
public void onPerformScaleAction_fullScreenMagnifierEnabled_handleScaleChange()
throws RemoteException {
final float newScale = 4.0f;
+ final boolean updatePersistence = true;
setMagnificationEnabled(MODE_FULLSCREEN);
- mMagnificationController.onPerformScaleAction(TEST_DISPLAY, newScale);
+ mMagnificationController.onPerformScaleAction(TEST_DISPLAY, newScale, updatePersistence);
verify(mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), eq(newScale),
anyFloat(), anyFloat(), anyBoolean(), anyInt());
@@ -619,12 +620,13 @@
public void onPerformScaleAction_windowMagnifierEnabled_handleScaleChange()
throws RemoteException {
final float newScale = 4.0f;
+ final boolean updatePersistence = false;
setMagnificationEnabled(MODE_WINDOW);
- mMagnificationController.onPerformScaleAction(TEST_DISPLAY, newScale);
+ mMagnificationController.onPerformScaleAction(TEST_DISPLAY, newScale, updatePersistence);
verify(mWindowMagnificationManager).setScale(eq(TEST_DISPLAY), eq(newScale));
- verify(mWindowMagnificationManager).persistScale(eq(TEST_DISPLAY));
+ verify(mWindowMagnificationManager, never()).persistScale(eq(TEST_DISPLAY));
}
@Test
@@ -1310,9 +1312,9 @@
}
@Override
- public void onPerformScaleAction(int displayId, float scale) {
+ public void onPerformScaleAction(int displayId, float scale, boolean updatePersistence) {
if (mCallback != null) {
- mCallback.onPerformScaleAction(displayId, scale);
+ mCallback.onPerformScaleAction(displayId, scale, updatePersistence);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index e8b337a..27e6ef1 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -576,12 +576,15 @@
@Test
public void onPerformScaleAction_magnifierEnabled_notifyAction() throws RemoteException {
final float newScale = 4.0f;
+ final boolean updatePersistence = true;
mWindowMagnificationManager.setConnection(mMockConnection.getConnection());
mWindowMagnificationManager.enableWindowMagnification(TEST_DISPLAY, 3.0f, NaN, NaN);
- mMockConnection.getConnectionCallback().onPerformScaleAction(TEST_DISPLAY, newScale);
+ mMockConnection.getConnectionCallback().onPerformScaleAction(
+ TEST_DISPLAY, newScale, updatePersistence);
- verify(mMockCallback).onPerformScaleAction(eq(TEST_DISPLAY), eq(newScale));
+ verify(mMockCallback).onPerformScaleAction(
+ eq(TEST_DISPLAY), eq(newScale), eq(updatePersistence));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
index 6c6b608..7e6883b 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputControllerTest.java
@@ -44,6 +44,7 @@
import com.android.server.LocalServices;
import com.android.server.input.InputManagerInternal;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -93,6 +94,11 @@
threadVerifier);
}
+ @After
+ public void tearDown() {
+ mInputManagerMockHelper.tearDown();
+ }
+
@Test
public void registerInputDevice_deviceCreation_hasDeviceId() {
final IBinder device1Token = new Binder("device1");
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
index 5cadc0a..3722247 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/InputManagerMockHelper.java
@@ -46,6 +46,7 @@
private final TestableLooper mTestableLooper;
private final InputController.NativeWrapper mNativeWrapperMock;
private final IInputManager mIInputManagerMock;
+ private final InputManagerGlobal.TestSession mInputManagerGlobalSession;
private final List<InputDevice> mDevices = new ArrayList<>();
private IInputDevicesChangedListener mDevicesChangedListener;
@@ -77,7 +78,13 @@
// Set a new instance of InputManager for testing that uses the IInputManager mock as the
// interface to the server.
- InputManagerGlobal.resetInstance(mIInputManagerMock);
+ mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock);
+ }
+
+ public void tearDown() {
+ if (mInputManagerGlobalSession != null) {
+ mInputManagerGlobalSession.close();
+ }
}
private long handleNativeOpenInputDevice(InvocationOnMock inv) {
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 4b801bc..d76d615 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -376,6 +376,7 @@
@After
public void tearDown() {
mDeviceImpl.close();
+ mInputManagerMockHelper.tearDown();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index ad1c60e..7478778 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -46,7 +46,6 @@
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_OPEN;
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_PERSONAL;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
-import static android.app.admin.PasswordMetrics.computeForPasswordOrPin;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
@@ -5479,8 +5478,7 @@
reset(mContext.spiedContext);
- PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin(
- "abcdXYZ5".getBytes(), /* isPin */ false);
+ PasswordMetrics passwordMetricsNoSymbols = metricsForPassword("abcdXYZ5");
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.isActivePasswordSufficient()).isTrue();
@@ -5507,8 +5505,7 @@
reset(mContext.spiedContext);
assertThat(dpm.isActivePasswordSufficient()).isFalse();
- PasswordMetrics passwordMetricsWithSymbols = computeForPasswordOrPin(
- "abcd.XY5".getBytes(), /* isPin */ false);
+ PasswordMetrics passwordMetricsWithSymbols = metricsForPassword("abcd.XY5");
setActivePasswordState(passwordMetricsWithSymbols);
assertThat(dpm.isActivePasswordSufficient()).isTrue();
@@ -5564,7 +5561,7 @@
parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("184342".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("184342"));
// Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly
// on the parent admin)
@@ -5685,7 +5682,7 @@
// Set a work challenge and verify profile.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
- .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("abcdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5710,7 +5707,7 @@
// Set a work challenge and verify profile.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
- .thenReturn(computeForPasswordOrPin("5156".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("5156"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5735,7 +5732,7 @@
// Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("acbdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("acbdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5758,7 +5755,7 @@
// Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("1234".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("1234"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5783,7 +5780,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("abcdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5806,7 +5803,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("51567548".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("51567548"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5831,7 +5828,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("abcdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5854,7 +5851,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("5156".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("5156"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -6909,7 +6906,7 @@
.thenReturn(CALLER_USER_HANDLE);
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(CALLER_USER_HANDLE))
- .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("asdf"));
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
}
@@ -6929,10 +6926,10 @@
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(CALLER_USER_HANDLE))
- .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("asdf"));
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(parentUser.id))
- .thenReturn(computeForPasswordOrPin("parentUser".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("parentUser"));
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
}
@@ -7654,15 +7651,13 @@
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
reset(mContext.spiedContext);
- PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin(
- "1234".getBytes(), /* isPin */ true);
+ PasswordMetrics passwordMetricsNoSymbols = metricsForPin("1234");
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_LOW);
assertThat(dpm.isActivePasswordSufficient()).isFalse();
reset(mContext.spiedContext);
- passwordMetricsNoSymbols = computeForPasswordOrPin(
- "84125312943a".getBytes(), /* isPin */ false);
+ passwordMetricsNoSymbols = metricsForPassword("84125312943a");
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
// using isActivePasswordSufficient
@@ -8837,4 +8832,12 @@
assumeTrue("device doesn't support deprecated password APIs",
isDeprecatedPasswordApisSupported());
}
+
+ private static PasswordMetrics metricsForPassword(String password) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPassword(password));
+ }
+
+ private static PasswordMetrics metricsForPin(String pin) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPin(pin));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/input/OWNERS b/services/tests/servicestests/src/com/android/server/input/OWNERS
deleted file mode 100644
index 6e9aa1d..0000000
--- a/services/tests/servicestests/src/com/android/server/input/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-include /services/core/java/com/android/server/input/OWNERS
-
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java b/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
index c9f00d7..d9b698e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserLifecycleStressTest.java
@@ -24,6 +24,7 @@
import android.app.ActivityManager;
import android.app.IStopUserCallback;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserManager;
@@ -35,6 +36,8 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+import com.android.compatibility.common.util.ShellUtils;
import com.android.internal.util.FunctionalUtils;
import org.junit.After;
@@ -46,6 +49,7 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* To run the test:
@@ -58,9 +62,14 @@
private static final String TAG = "UserLifecycleStressTest";
// TODO: Make this smaller once we have improved it.
private static final int TIMEOUT_IN_SECOND = 40;
+ private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
+
private static final int NUM_ITERATIONS = 8;
private static final int WAIT_BEFORE_STOP_USER_IN_SECOND = 3;
+ /** Name of users/profiles in the test. Users with this name may be freely removed. */
+ private static final String TEST_USER_NAME = "UserLifecycleStressTest_test_user";
+
private Context mContext;
private UserManager mUserManager;
private ActivityManager mActivityManager;
@@ -75,6 +84,7 @@
mUserSwitchWaiter = new UserSwitchWaiter(TAG, TIMEOUT_IN_SECOND);
mRemoveGuestOnExitOriginalValue = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.REMOVE_GUEST_ON_EXIT);
+ waitForBroadcastBarrier(); // isolate tests from each other
}
@After
@@ -82,6 +92,7 @@
mUserSwitchWaiter.close();
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.REMOVE_GUEST_ON_EXIT, mRemoveGuestOnExitOriginalValue);
+ waitForBroadcastBarrier(); // isolate tests from each other
}
/**
@@ -91,8 +102,10 @@
@Test
public void stopManagedProfileStressTest() throws RemoteException, InterruptedException {
for (int i = 0; i < NUM_ITERATIONS; i++) {
- final UserInfo userInfo = mUserManager.createProfileForUser("TestUser",
- UserManager.USER_TYPE_PROFILE_MANAGED, 0, mActivityManager.getCurrentUser());
+ logIteration(i, "stopManagedProfileStressTest");
+
+ final UserInfo userInfo = mUserManager.createProfileForUser(TEST_USER_NAME,
+ UserManager.USER_TYPE_PROFILE_MANAGED, 0, ActivityManager.getCurrentUser());
assertThat(userInfo).isNotNull();
try {
assertWithMessage("Failed to start the profile")
@@ -109,6 +122,35 @@
}
/**
+ * Create a user, and then remove it immediately after starting it in background
+ * {@link #NUM_ITERATIONS} times in a row.
+ * Check device is not crashed when user data directory is deleted while some other processes
+ * might still be trying to access those deleted files.
+ */
+ @Test
+ public void removeRecentlyStartedUserStressTest() throws RemoteException, InterruptedException {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ logIteration(i, "removeRecentlyStartedUserStressTest");
+
+ Log.d(TAG, "Creating a new user");
+ final UserInfo userInfo = mUserManager.createUser(TEST_USER_NAME,
+ UserManager.USER_TYPE_FULL_SECONDARY, 0);
+ assertWithMessage("Failed to create the user")
+ .that(userInfo)
+ .isNotNull();
+ try {
+ Log.d(TAG, "Starting user " + userInfo.id);
+ startUserInBackgroundAndWaitForUserStartedBroadcast(userInfo.id);
+ } finally {
+ Log.d(TAG, "Removing user " + userInfo.id);
+ assertWithMessage("Failed to remove the user " + userInfo.id)
+ .that(removeUser(userInfo.id))
+ .isTrue();
+ }
+ }
+ }
+
+ /**
* Starts over the guest user {@link #NUM_ITERATIONS} times in a row.
*
* Starting over the guest means the following:
@@ -130,10 +172,9 @@
int nextGuestId = guestUsers.isEmpty() ? USER_NULL : guestUsers.get(0).id;
for (int i = 0; i < NUM_ITERATIONS; i++) {
- final int currentGuestId = nextGuestId;
+ logIteration(i, "switchToExistingGuestAndStartOverStressTest");
- Log.d(TAG, "switchToExistingGuestAndStartOverStressTest"
- + " - Run " + (i + 1) + " / " + NUM_ITERATIONS);
+ final int currentGuestId = nextGuestId;
if (currentGuestId != USER_NULL) {
Log.d(TAG, "Switching to the existing guest");
@@ -173,6 +214,25 @@
Log.d(TAG, "testSwitchToExistingGuestAndStartOver - End");
}
+ private boolean removeUser(int userId) {
+ if (!mUserManager.removeUser(userId)) {
+ return false;
+ }
+ try {
+ final long startTime = System.currentTimeMillis();
+ final long timeoutInMs = TIMEOUT_IN_SECOND * 1000;
+ while (mUserManager.getUserInfo(userId) != null
+ && System.currentTimeMillis() - startTime < timeoutInMs) {
+ TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } catch (Exception e) {
+ // Ignore
+ }
+ return mUserManager.getUserInfo(userId) == null;
+ }
+
/** Stops the given user and waits for the stop to finish. */
private void stopUser(int userId) throws RemoteException, InterruptedException {
runWithLatch("stop user", countDownLatch -> {
@@ -204,6 +264,40 @@
}
/**
+ * Start user in background and wait for {@link Intent#ACTION_USER_STARTED} broadcast.
+ * <p> To start in foreground instead, see {@link #switchUser(int)}.
+ * <p> This should always be used for profiles since profiles cannot be started in foreground.
+ */
+ private void startUserInBackgroundAndWaitForUserStartedBroadcast(int userId) {
+ runWithBlockingBroadcastReceiver("start user and wait for ACTION_USER_STARTED broadcast",
+ userId, Intent.ACTION_USER_STARTED,
+ () -> ActivityManager.getService().startUserInBackground(userId));
+ }
+
+ /**
+ * Calls the given runnable and expects the given broadcast to be received before timeout,
+ * or fails the test otherwise.
+ * @param tag tag for logging
+ * @param userId id of the user to register the broadcast receiver with
+ * see {@link Context#registerReceiverAsUser}
+ * @param action action of the broadcast intent filter i.e. {@link Intent#ACTION_USER_STARTED}
+ * @param runnable this will be called after registering the broadcast receiver
+ */
+ private void runWithBlockingBroadcastReceiver(String tag, int userId, String action,
+ FunctionalUtils.ThrowingRunnable runnable) {
+ try (BlockingBroadcastReceiver blockingBroadcastReceiver = new BlockingBroadcastReceiver(
+ mContext, action,
+ intent -> intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL) == userId)) {
+ blockingBroadcastReceiver.setTimeout(TIMEOUT_IN_SECOND);
+ blockingBroadcastReceiver.registerForAllUsers();
+ runnable.run();
+ assertWithMessage("Took more than " + TIMEOUT_IN_SECOND + "s to " + tag)
+ .that(blockingBroadcastReceiver.awaitForBroadcast())
+ .isNotNull();
+ }
+ }
+
+ /**
* Calls the given consumer with a CountDownLatch parameter, and expects it's countDown() method
* to be called before timeout, or fails the test otherwise.
*/
@@ -222,5 +316,20 @@
final long elapsedTime = System.currentTimeMillis() - startTime;
Log.d(TAG, tag + " takes " + elapsedTime + " ms");
}
+
+ private void logIteration(int iteration, String testMethodName) {
+ Log.d(TAG, testMethodName + " - Iteration " + (iteration + 1) + " / " + NUM_ITERATIONS);
+ }
+
+ private static void waitForBroadcastBarrier() {
+ try {
+ Log.d(TAG, "Starting to waitForBroadcastBarrier");
+ ShellUtils.runShellCommandWithTimeout("am wait-for-broadcast-barrier",
+ TIMEOUT_IN_SECOND);
+ Log.d(TAG, "waitForBroadcastBarrier is finished");
+ } catch (TimeoutException e) {
+ Log.e(TAG, "Timeout while running waitForBroadcastBarrier", e);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index 2ab79fc..f3c17a8 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -77,6 +77,7 @@
private TestLooper mTestLooper;
private ContextWrapper mContextSpy;
+ private InputManagerGlobal.TestSession mInputManagerGlobalSession;
private InputManager mInputManager;
private InputDeviceDelegate mInputDeviceDelegate;
private IInputDevicesChangedListener mIInputDevicesChangedListener;
@@ -84,7 +85,7 @@
@Before
public void setUp() throws Exception {
mTestLooper = new TestLooper();
- InputManagerGlobal.resetInstance(mIInputManagerMock);
+ mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
mInputManager = new InputManager(mContextSpy);
@@ -100,7 +101,9 @@
@After
public void tearDown() throws Exception {
- InputManagerGlobal.clearInstance();
+ if (mInputManagerGlobalSession != null) {
+ mInputManagerGlobalSession.close();
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index c805fc5..9a911f4 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -186,14 +186,14 @@
private VirtualDeviceManagerInternal.VirtualDisplayListener mRegisteredVirtualDisplayListener;
private VirtualDeviceManagerInternal.AppsOnVirtualDeviceListener
mRegisteredAppsOnVirtualDeviceListener;
-
+ private InputManagerGlobal.TestSession mInputManagerGlobalSession;
private InputManager mInputManager;
@Before
public void setUp() throws Exception {
mTestLooper = new TestLooper();
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
- InputManagerGlobal.resetInstance(mIInputManagerMock);
+ mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock);
mVibrationConfig = new VibrationConfig(mContextSpy.getResources());
ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
@@ -268,7 +268,9 @@
LocalServices.removeServiceForTest(PowerManagerInternal.class);
// Ignore potential exceptions about the looper having never dispatched any messages.
mTestLooper.stopAutoDispatchAndIgnoreExceptions();
- InputManagerGlobal.clearInstance();
+ if (mInputManagerGlobalSession != null) {
+ mInputManagerGlobalSession.close();
+ }
}
private VibratorManagerService createSystemReadyService() {
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 541739d..2136811 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -1933,6 +1933,36 @@
}, 20, 30);
}
+ @Test
+ public void isComponentEnabledForCurrentProfiles_profileUserId() {
+ final int profileUserId = 10;
+ when(mUserProfiles.isProfileUser(profileUserId)).thenReturn(true);
+ // Only approve for parent user (0)
+ mService.addApprovedList("pkg1/cmp1:pkg2/cmp2:pkg3/cmp3", 0, true);
+
+ // Test that the component is enabled after calling rebindServices with profile userId (10)
+ mService.rebindServices(false, profileUserId);
+ assertThat(mService.isComponentEnabledForCurrentProfiles(
+ new ComponentName("pkg1", "cmp1"))).isTrue();
+ }
+
+ @Test
+ public void isComponentEnabledForCurrentProfiles_profileUserId_NAS() {
+ final int profileUserId = 10;
+ when(mUserProfiles.isProfileUser(profileUserId)).thenReturn(true);
+ // Do not rebind for parent users (NAS use-case)
+ ManagedServices service = spy(mService);
+ when(service.allowRebindForParentUser()).thenReturn(false);
+
+ // Only approve for parent user (0)
+ service.addApprovedList("pkg1/cmp1:pkg2/cmp2:pkg3/cmp3", 0, true);
+
+ // Test that the component is disabled after calling rebindServices with profile userId (10)
+ service.rebindServices(false, profileUserId);
+ assertThat(service.isComponentEnabledForCurrentProfiles(
+ new ComponentName("pkg1", "cmp1"))).isFalse();
+ }
+
private void mockServiceInfoWithMetaData(List<ComponentName> componentNames,
ManagedServices service, ArrayMap<ComponentName, Bundle> metaDatas)
throws RemoteException {
@@ -2276,6 +2306,11 @@
protected String getRequiredPermission() {
return null;
}
+
+ @Override
+ protected boolean allowRebindForParentUser() {
+ return true;
+ }
}
class TestManagedServicesSettings extends TestManagedServices {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
index 6f7bace..082b675 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
@@ -16,24 +16,44 @@
package com.android.server.notification;
+import android.annotation.Nullable;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import com.google.common.base.MoreObjects;
+
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
public class NotificationChannelLoggerFake implements NotificationChannelLogger {
static class CallRecord {
- public NotificationChannelEvent event;
- CallRecord(NotificationChannelEvent event) {
+ public final NotificationChannelEvent event;
+ @Nullable public final String channelId;
+
+ CallRecord(NotificationChannelEvent event, @Nullable String channelId) {
this.event = event;
+ this.channelId = channelId;
}
@Override
public String toString() {
- return "CallRecord{" +
- "event=" + event +
- '}';
+ return MoreObjects.toStringHelper(this)
+ .add("event", event)
+ .add(channelId, channelId)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof CallRecord other)
+ && Objects.equals(this.event, other.event)
+ && Objects.equals(this.channelId, other.channelId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(event, channelId);
}
}
@@ -47,20 +67,24 @@
return mCalls.get(index);
}
+ void clear() {
+ mCalls.clear();
+ }
+
@Override
public void logNotificationChannel(NotificationChannelEvent event, NotificationChannel channel,
int uid, String pkg, int oldImportance, int newImportance) {
- mCalls.add(new CallRecord(event));
+ mCalls.add(new CallRecord(event, channel.getId()));
}
@Override
public void logNotificationChannelGroup(NotificationChannelEvent event,
NotificationChannelGroup channelGroup, int uid, String pkg, boolean wasBlocked) {
- mCalls.add(new CallRecord(event));
+ mCalls.add(new CallRecord(event, channelGroup.getId()));
}
@Override
public void logAppEvent(NotificationChannelEvent event, int uid, String pkg) {
- mCalls.add(new CallRecord(event));
+ mCalls.add(new CallRecord(event, null));
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e49b290..7e81ef2 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -62,6 +62,8 @@
import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Build.VERSION_CODES.P;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
+import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
@@ -83,6 +85,9 @@
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.SHOW_STICKY_HUN_FOR_DENIED_FSI;
import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.WAKE_LOCK_FOR_POSTING_NOTIFICATION;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
+import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
+import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
@@ -186,6 +191,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
+import android.os.Parcelable;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.Process;
@@ -716,6 +722,7 @@
@After
public void assertAllWakeLocksReleased() {
+ waitForIdle(); // Finish async work.
for (WakeLock wakeLock : mAcquiredWakeLocks) {
assertThat(wakeLock.isHeld()).isFalse();
}
@@ -5910,6 +5917,26 @@
}
@Test
+ public void testVisitUris_wearableExtender() {
+ Icon actionIcon = Icon.createWithContentUri("content://media/action");
+ Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
+ PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
+ Notification n = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
+ .extend(new Notification.WearableExtender().addAction(
+ new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
+ .build();
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ verify(visitor).accept(eq(actionIcon.getUri()));
+ verify(visitor).accept(eq(wearActionIcon.getUri()));
+ }
+
+ @Test
public void testSetNotificationPolicy_preP_setOldFields() {
ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class);
mService.mZenModeHelper = mZenModeHelper;
@@ -11242,7 +11269,6 @@
// Given: a call notification has the flag FLAG_ONGOING_EVENT set
// feature flag: ALLOW_DISMISS_ONGOING is on
mTestFlagResolver.setFlagOverride(ALLOW_DISMISS_ONGOING, true);
- when(mTelecomManager.isInManagedCall()).thenReturn(true);
Person person = new Person.Builder()
.setName("caller")
@@ -12097,6 +12123,70 @@
assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111); // old
}
+ @Test
+ public void enqueueNotification_allowlistsPendingIntents() throws RemoteException {
+ PendingIntent contentIntent = createPendingIntent("content");
+ PendingIntent actionIntent1 = createPendingIntent("action1");
+ PendingIntent actionIntent2 = createPendingIntent("action2");
+ Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentIntent(contentIntent)
+ .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build())
+ .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build())
+ .build();
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 1,
+ parcelAndUnparcel(n, Notification.CREATOR), mUserId);
+
+ verify(mAmi, times(3)).setPendingIntentAllowlistDuration(
+ any(), any(), anyLong(),
+ eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
+ eq(REASON_NOTIFICATION_SERVICE), any());
+ verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(),
+ any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
+ }
+
+ @Test
+ public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion()
+ throws RemoteException {
+ PendingIntent contentIntent = createPendingIntent("content");
+ PendingIntent actionIntent = createPendingIntent("action");
+ PendingIntent publicContentIntent = createPendingIntent("publicContent");
+ PendingIntent publicActionIntent = createPendingIntent("publicAction");
+ Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID)
+ .setContentIntent(contentIntent)
+ .addAction(new Notification.Action.Builder(null, "action", actionIntent).build())
+ .setPublicVersion(new Notification.Builder(mContext, "channel")
+ .setContentIntent(publicContentIntent)
+ .addAction(new Notification.Action.Builder(
+ null, "publicAction", publicActionIntent).build())
+ .build())
+ .build();
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", 1,
+ parcelAndUnparcel(source, Notification.CREATOR), mUserId);
+
+ verify(mAmi, times(4)).setPendingIntentAllowlistDuration(
+ any(), any(), anyLong(),
+ eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED),
+ eq(REASON_NOTIFICATION_SERVICE), any());
+ verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(),
+ any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
+ }
+
+ private static <T extends Parcelable> T parcelAndUnparcel(T source,
+ Parcelable.Creator<T> creator) {
+ Parcel parcel = Parcel.obtain();
+ source.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return creator.createFromParcel(parcel);
+ }
+
+ private PendingIntent createPendingIntent(String action) {
+ return PendingIntent.getActivity(mContext, 0,
+ new Intent(action).setPackage(mContext.getPackageName()),
+ PendingIntent.FLAG_MUTABLE);
+ }
+
private void setDpmAppOppsExemptFromDismissal(boolean isOn) {
DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
index 0b147c3..b522cab 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerTest.java
@@ -18,6 +18,14 @@
import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
+import static android.service.notification.NotificationStats.DISMISSAL_OTHER;
+
+import static com.android.server.notification.NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK;
+import static com.android.server.notification.NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED;
+import static com.android.server.notification.NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_OTHER;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED;
import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED;
@@ -208,4 +216,18 @@
/* eventType= */ NOTIFICATION_POSTED);
assertEquals(FrameworkStatsLog.NOTIFICATION_REPORTED__FSI_STATE__NO_FSI, fsiState);
}
+
+ @Test
+ public void testBubbleGroupSummaryDismissal() {
+ assertEquals(NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED,
+ NotificationRecordLogger.NotificationCancelledEvent.fromCancelReason(
+ REASON_GROUP_SUMMARY_CANCELED, DISMISSAL_BUBBLE));
+ }
+
+ @Test
+ public void testOtherNotificationCancel() {
+ assertEquals(NOTIFICATION_CANCEL_USER_OTHER,
+ NotificationRecordLogger.NotificationCancelledEvent.fromCancelReason(
+ REASON_CANCEL, DISMISSAL_OTHER));
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index d32289d..121e296 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -67,6 +67,8 @@
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@@ -88,7 +90,6 @@
// This list should be emptied! Items can be removed as bugs are fixed.
private static final Multimap<Class<?>, String> KNOWN_BAD =
ImmutableMultimap.<Class<?>, String>builder()
- .put(Notification.WearableExtender.class, "addAction") // TODO: b/281044385
.put(Person.Builder.class, "setUri") // TODO: b/281044385
.put(RemoteViews.class, "setRemoteAdapter") // TODO: b/281044385
.build();
@@ -164,7 +165,7 @@
/* extenderClass= */ Notification.WearableExtender.class,
/* actionExtenderClass= */ Notification.Action.WearableExtender.class,
/* includeRemoteViews= */ true);
- assertThat(notification.includedUris.size()).isAtLeast(730);
+ assertThat(notification.includedUris.size()).isAtLeast(900);
}
@Test
@@ -450,19 +451,43 @@
Set<Class<?>> excludingClasses, SpecialParameterGenerator specialGenerator) {
Log.i(TAG, "About to generate parameters for " + ReflectionUtils.methodToString(executable)
+ " in " + where);
- Class<?>[] parameterTypes = executable.getParameterTypes();
+ Type[] parameterTypes = executable.getGenericParameterTypes();
Object[] parameterValues = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
- parameterValues[i] = generateObject(
+ parameterValues[i] = generateParameter(
parameterTypes[i],
where.plus(executable,
- String.format("[%d,%s]", i, parameterTypes[i].getName())),
+ String.format("[%d,%s]", i, parameterTypes[i].getTypeName())),
excludingClasses,
specialGenerator);
}
return parameterValues;
}
+ private static Object generateParameter(Type parameterType, Location where,
+ Set<Class<?>> excludingClasses, SpecialParameterGenerator specialGenerator) {
+ if (parameterType instanceof Class<?> parameterClass) {
+ return generateObject(
+ parameterClass,
+ where,
+ excludingClasses,
+ specialGenerator);
+ } else if (parameterType instanceof ParameterizedType parameterizedType) {
+ if (parameterizedType.getRawType().equals(List.class)
+ && parameterizedType.getActualTypeArguments()[0] instanceof Class<?>) {
+ ArrayList listValue = new ArrayList();
+ for (int i = 0; i < NUM_ELEMENTS_IN_ARRAY; i++) {
+ listValue.add(
+ generateObject((Class<?>) parameterizedType.getActualTypeArguments()[0],
+ where, excludingClasses, specialGenerator));
+ }
+ return listValue;
+ }
+ }
+ throw new IllegalArgumentException(
+ "I have no idea how to produce a(n) " + parameterType + ", sorry");
+ }
+
private static class ReflectionUtils {
static Set<Class<?>> getConcreteSubclasses(Class<?> clazz, Class<?> containerClass) {
return Arrays.stream(containerClass.getDeclaredClasses())
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 47340c1..ea670bd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -18,8 +18,19 @@
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
+import static android.app.Notification.VISIBILITY_PRIVATE;
+import static android.app.Notification.VISIBILITY_SECRET;
+import static android.app.NotificationChannel.ALLOW_BUBBLE_ON;
import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT;
+import static android.app.NotificationChannel.DEFAULT_ALLOW_BUBBLE;
+import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE;
import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
+import static android.app.NotificationChannel.USER_LOCKED_LIGHTS;
+import static android.app.NotificationChannel.USER_LOCKED_PRIORITY;
+import static android.app.NotificationChannel.USER_LOCKED_SHOW_BADGE;
+import static android.app.NotificationChannel.USER_LOCKED_SOUND;
+import static android.app.NotificationChannel.USER_LOCKED_VIBRATION;
+import static android.app.NotificationChannel.USER_LOCKED_VISIBILITY;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE;
import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED;
@@ -29,16 +40,18 @@
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION;
import static android.media.AudioAttributes.USAGE_NOTIFICATION;
import static android.os.UserHandle.USER_SYSTEM;
import static android.util.StatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
-import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
-import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_ID_FIELD_NUMBER;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_NAME_FIELD_NUMBER;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IMPORTANCE_FIELD_NUMBER;
@@ -47,10 +60,12 @@
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DEMOTED_CONVERSATION_FIELD_NUMBER;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_IMPORTANT_CONVERSATION_FIELD_NUMBER;
import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.UID_FIELD_NUMBER;
+import static com.android.server.notification.NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER;
import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT;
import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertNull;
@@ -124,6 +139,8 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags;
+import com.android.internal.config.sysui.TestableFlagResolver;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.os.AtomsProto.PackageNotificationPreferences;
@@ -134,6 +151,7 @@
import org.json.JSONArray;
import org.json.JSONObject;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -181,6 +199,9 @@
private static final Uri FILE_SOUND_URI =
Uri.parse("file://" + TEST_AUTHORITY + "/product/media/test.ogg");
+ private static final Uri DEFAULT_SOUND_URI = Uri.parse(
+ "content://settings/system/notification_sound");
+
@Mock PermissionHelper mPermissionHelper;
@Mock RankingHandler mHandler;
@Mock PackageManager mPm;
@@ -325,6 +346,11 @@
NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN);
}
+ @After
+ public void tearDown() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = null;
+ }
+
private ByteArrayOutputStream writeXmlAndPurge(
String pkg, int uid, boolean forBackup, int userId, String... channelIds)
throws Exception {
@@ -509,7 +535,7 @@
channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel2.enableLights(true);
channel2.setBypassDnd(true);
- channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel2.setLockscreenVisibility(VISIBILITY_SECRET);
channel2.enableVibration(true);
channel2.setGroup(ncg.getId());
channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
@@ -577,7 +603,7 @@
channel2.setSound(SOUND_URI, mAudioAttributes);
channel2.enableLights(true);
channel2.setBypassDnd(true);
- channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel2.setLockscreenVisibility(VISIBILITY_SECRET);
channel2.enableVibration(false);
channel2.setGroup(ncg.getId());
channel2.setLightColor(Color.BLUE);
@@ -1054,7 +1080,7 @@
channel2.setSound(null, null);
channel2.enableLights(true);
channel2.setBypassDnd(true);
- channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel2.setLockscreenVisibility(VISIBILITY_SECRET);
channel2.enableVibration(false);
channel2.setGroup(ncg.getId());
channel2.setLightColor(Color.BLUE);
@@ -1140,7 +1166,7 @@
channel2.setSound(null, null);
channel2.enableLights(true);
channel2.setBypassDnd(true);
- channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel2.setLockscreenVisibility(VISIBILITY_SECRET);
channel2.enableVibration(false);
channel2.setGroup(ncg.getId());
channel2.setLightColor(Color.BLUE);
@@ -1228,7 +1254,7 @@
channel2.setSound(null, null);
channel2.enableLights(true);
channel2.setBypassDnd(true);
- channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel2.setLockscreenVisibility(VISIBILITY_SECRET);
channel2.enableVibration(false);
channel2.setGroup(ncg.getId());
channel2.setLightColor(Color.BLUE);
@@ -1621,7 +1647,7 @@
NotificationChannel.DEFAULT_CHANNEL_ID, false);
assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
assertFalse(updated.canBypassDnd());
- assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility());
+ assertEquals(VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility());
assertEquals(0, updated.getUserLockedFields());
}
@@ -1649,9 +1675,9 @@
+ "<package name=\"" + PKG_N_MR1
+ "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
+ "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
- + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID_N_MR1 + "\" />\n"
+ + VISIBILITY_SECRET + "\"" + " uid=\"" + UID_N_MR1 + "\" />\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" visibility=\""
- + Notification.VISIBILITY_PRIVATE + "\" />\n"
+ + VISIBILITY_PRIVATE + "\" />\n"
+ "</ranking>";
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
@@ -1663,10 +1689,10 @@
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
assertTrue(updated1.canBypassDnd());
- assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
+ assertEquals(VISIBILITY_SECRET, updated1.getLockscreenVisibility());
assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE
- | NotificationChannel.USER_LOCKED_PRIORITY
- | NotificationChannel.USER_LOCKED_VISIBILITY,
+ | USER_LOCKED_PRIORITY
+ | USER_LOCKED_VISIBILITY,
updated1.getUserLockedFields());
// No Default Channel created for updated packages
@@ -1811,7 +1837,7 @@
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.enableLights(true);
channel.setBypassDnd(true);
- channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false,
SYSTEM_UID, true));
@@ -1838,7 +1864,7 @@
public void testUpdate_preUpgrade_updatesAppFields() throws Exception {
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
- assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
+ assertEquals(VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
NotificationChannel defaultChannel = mHelper.getNotificationChannel(
@@ -1847,7 +1873,7 @@
defaultChannel.setShowBadge(false);
defaultChannel.setImportance(IMPORTANCE_NONE);
defaultChannel.setBypassDnd(true);
- defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ defaultChannel.setLockscreenVisibility(VISIBILITY_SECRET);
mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true,
@@ -1856,7 +1882,7 @@
// ensure app level fields are changed
assertFalse(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
- assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG_N_MR1,
+ assertEquals(VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG_N_MR1,
UID_N_MR1));
}
@@ -1868,13 +1894,13 @@
SYSTEM_UID, true);
assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
- assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
+ assertEquals(VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_O, UID_O));
channel.setShowBadge(false);
channel.setImportance(IMPORTANCE_NONE);
channel.setBypassDnd(true);
- channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
mHelper.updateNotificationChannel(PKG_O, UID_O, channel, true,
SYSTEM_UID, true);
@@ -1882,7 +1908,7 @@
// ensure app level fields are not changed
assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
- assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
+ assertEquals(VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_O, UID_O));
}
@@ -1894,13 +1920,13 @@
SYSTEM_UID, true);
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
- assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
+ assertEquals(VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
channel.setShowBadge(false);
channel.setImportance(IMPORTANCE_NONE);
channel.setBypassDnd(true);
- channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true,
SYSTEM_UID, true);
@@ -1911,7 +1937,7 @@
defaultChannel.setShowBadge(false);
defaultChannel.setImportance(IMPORTANCE_NONE);
defaultChannel.setBypassDnd(true);
- defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ defaultChannel.setLockscreenVisibility(VISIBILITY_SECRET);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true,
SYSTEM_UID, true);
@@ -1919,7 +1945,7 @@
// ensure app level fields are not changed
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
- assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
+ assertEquals(VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
}
@@ -1935,7 +1961,7 @@
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.enableLights(true);
channel.setBypassDnd(true);
- channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
channel.setShowBadge(true);
channel.setAllowBubbles(false);
channel.setImportantConversation(true);
@@ -1954,7 +1980,7 @@
assertEquals(channel.getName(), savedChannel.getName());
assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
assertFalse(savedChannel.canBypassDnd());
- assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
+ assertFalse(VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
assertFalse(channel.isImportantConversation());
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
assertEquals(channel.canBubble(), savedChannel.canBubble());
@@ -1969,7 +1995,7 @@
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.enableLights(true);
channel.setBypassDnd(true);
- channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
channel.setShowBadge(true);
channel.setAllowBubbles(false);
int lockMask = 0;
@@ -1987,7 +2013,7 @@
assertEquals(channel.getName(), savedChannel.getName());
assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
assertFalse(savedChannel.canBypassDnd());
- assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
+ assertFalse(VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
assertEquals(channel.canBubble(), savedChannel.canBubble());
}
@@ -1998,7 +2024,7 @@
mHelper.clearLockedFieldsLocked(channel);
assertEquals(0, channel.getUserLockedFields());
- channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
+ channel.lockFields(USER_LOCKED_PRIORITY
| NotificationChannel.USER_LOCKED_IMPORTANCE);
mHelper.clearLockedFieldsLocked(channel);
assertEquals(0, channel.getUserLockedFields());
@@ -2012,19 +2038,19 @@
final NotificationChannel update1 = getChannel();
update1.setSound(new Uri.Builder().scheme("test").build(),
new AudioAttributes.Builder().build());
- update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
+ update1.lockFields(USER_LOCKED_PRIORITY);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
- | NotificationChannel.USER_LOCKED_SOUND,
+ assertEquals(USER_LOCKED_PRIORITY
+ | USER_LOCKED_SOUND,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
.getUserLockedFields());
NotificationChannel update2 = getChannel();
update2.enableVibration(true);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
- | NotificationChannel.USER_LOCKED_SOUND
- | NotificationChannel.USER_LOCKED_VIBRATION,
+ assertEquals(USER_LOCKED_PRIORITY
+ | USER_LOCKED_SOUND
+ | USER_LOCKED_VIBRATION,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
.getUserLockedFields());
}
@@ -2037,15 +2063,15 @@
final NotificationChannel update1 = getChannel();
update1.setVibrationPattern(new long[]{7945, 46 ,246});
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
+ assertEquals(USER_LOCKED_VIBRATION,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
update2.enableLights(true);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
- | NotificationChannel.USER_LOCKED_LIGHTS,
+ assertEquals(USER_LOCKED_VIBRATION
+ | USER_LOCKED_LIGHTS,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
.getUserLockedFields());
}
@@ -2058,7 +2084,7 @@
final NotificationChannel update1 = getChannel();
update1.setLightColor(Color.GREEN);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
+ assertEquals(USER_LOCKED_LIGHTS,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
.getUserLockedFields());
@@ -2066,7 +2092,7 @@
update2.setImportance(IMPORTANCE_DEFAULT);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true,
SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
+ assertEquals(USER_LOCKED_LIGHTS
| NotificationChannel.USER_LOCKED_IMPORTANCE,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
.getUserLockedFields());
@@ -2083,24 +2109,24 @@
final NotificationChannel update1 = getChannel();
update1.setBypassDnd(true);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
+ assertEquals(USER_LOCKED_PRIORITY,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false)
.getUserLockedFields());
final NotificationChannel update2 = getChannel();
- update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ update2.setLockscreenVisibility(VISIBILITY_SECRET);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
- | NotificationChannel.USER_LOCKED_VISIBILITY,
+ assertEquals(USER_LOCKED_PRIORITY
+ | USER_LOCKED_VISIBILITY,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false)
.getUserLockedFields());
final NotificationChannel update3 = getChannel();
update3.setShowBadge(false);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update3, true, SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
- | NotificationChannel.USER_LOCKED_VISIBILITY
- | NotificationChannel.USER_LOCKED_SHOW_BADGE,
+ assertEquals(USER_LOCKED_PRIORITY
+ | USER_LOCKED_VISIBILITY
+ | USER_LOCKED_SHOW_BADGE,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update3.getId(), false)
.getUserLockedFields());
}
@@ -2117,7 +2143,7 @@
update.setAllowBubbles(true);
mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true,
SYSTEM_UID, true);
- assertEquals(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE,
+ assertEquals(USER_LOCKED_ALLOW_BUBBLE,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false)
.getUserLockedFields());
}
@@ -2153,7 +2179,7 @@
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.enableLights(true);
channel.setBypassDnd(true);
- channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{100, 67, 145, 156});
@@ -2181,7 +2207,7 @@
channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
channel.enableLights(true);
channel.setBypassDnd(true);
- channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
+ channel.setLockscreenVisibility(VISIBILITY_PRIVATE);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{100, 67, 145, 156});
channelMap.put(channel.getId(), channel);
@@ -5115,6 +5141,231 @@
}
@Test
+ public void testUpdateConversationParent_updatesConversations() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
+ .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
+
+ NotificationChannel parent =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel convoA = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
+ convoA.setConversationId(parent.getId(), "A");
+ mHelper.createNotificationChannel(PKG_O, UID_O, convoA, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel convoB = new NotificationChannel("B", "With B", IMPORTANCE_DEFAULT);
+ convoB.setConversationId(parent.getId(), "B");
+ mHelper.createNotificationChannel(PKG_O, UID_O, convoB, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "messages", /* includeDeleted= */
+ false).shouldVibrate()).isFalse();
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A",
+ /* includeDeleted= */ false).shouldVibrate()).isFalse();
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "B",
+ /* includeDeleted= */ false).shouldVibrate()).isFalse();
+ mLogger.clear();
+
+ NotificationChannel parentUpdate = cloneChannel(parent);
+ parentUpdate.enableVibration(true);
+ mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, UID_O,
+ /* fromSystemOrSystemUi= */ true);
+
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "messages",
+ /* includeDeleted= */ false).shouldVibrate()).isTrue();
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A",
+ /* includeDeleted= */ false).shouldVibrate()).isTrue();
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "B",
+ /* includeDeleted= */ false).shouldVibrate()).isTrue();
+
+ // Verify that the changes to parent and children were logged.
+ assertThat(mLogger.getCalls()).containsExactly(
+ new NotificationChannelLoggerFake.CallRecord(
+ NOTIFICATION_CHANNEL_UPDATED_BY_USER, "messages"),
+ new NotificationChannelLoggerFake.CallRecord(
+ NOTIFICATION_CHANNEL_UPDATED_BY_USER, "A"),
+ new NotificationChannelLoggerFake.CallRecord(
+ NOTIFICATION_CHANNEL_UPDATED_BY_USER, "B"))
+ .inOrder();
+ }
+
+ @Test
+ public void testUpdateConversationParent_updatesUnlockedFields() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
+ .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
+
+ NotificationChannel parent =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
+ convo.setConversationId(parent.getId(), "A");
+ mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ convo.getId(), /* includeDeleted= */ false);
+ assertThat(originalChild.canBypassDnd()).isFalse();
+ assertThat(originalChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_NO_OVERRIDE);
+ assertThat(originalChild.getImportance()).isEqualTo(IMPORTANCE_DEFAULT);
+ assertThat(originalChild.shouldShowLights()).isFalse();
+ assertThat(originalChild.getSound()).isEqualTo(DEFAULT_SOUND_URI);
+ assertThat(originalChild.shouldVibrate()).isFalse();
+ assertThat(originalChild.canShowBadge()).isTrue();
+ assertThat(originalChild.getAllowBubbles()).isEqualTo(DEFAULT_ALLOW_BUBBLE);
+
+ NotificationChannel parentUpdate = cloneChannel(parent);
+ parentUpdate.setBypassDnd(true);
+ parentUpdate.setLockscreenVisibility(VISIBILITY_SECRET);
+ parentUpdate.setImportance(IMPORTANCE_HIGH);
+ parentUpdate.enableLights(true);
+ parentUpdate.setSound(SOUND_URI, mAudioAttributes);
+ parentUpdate.enableVibration(true);
+ parentUpdate.setShowBadge(false);
+ parentUpdate.setAllowBubbles(true);
+ mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
+ UID_O, /* fromSystemOrSystemUi= */ true);
+
+ NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ "A", /* includeDeleted= */ false);
+ assertThat(updatedChild.canBypassDnd()).isTrue();
+ assertThat(updatedChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_SECRET);
+ assertThat(updatedChild.getImportance()).isEqualTo(IMPORTANCE_HIGH);
+ assertThat(updatedChild.shouldShowLights()).isTrue();
+ assertThat(updatedChild.getSound()).isEqualTo(SOUND_URI);
+ assertThat(updatedChild.shouldVibrate()).isTrue();
+ assertThat(updatedChild.canShowBadge()).isFalse();
+ assertThat(updatedChild.getAllowBubbles()).isEqualTo(ALLOW_BUBBLE_ON);
+ }
+
+ @Test
+ public void testUpdateConversationParent_doesNotUpdateLockedFields() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
+ .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
+ NotificationChannel parent =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
+ convo.setConversationId(parent.getId(), "A");
+ mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ // Directly update the child to lock every field.
+ // Normally this would be the result of one or more "fromUser" updates with modified fields.
+ convo.lockFields(
+ USER_LOCKED_PRIORITY | USER_LOCKED_VISIBILITY | USER_LOCKED_IMPORTANCE
+ | USER_LOCKED_LIGHTS | USER_LOCKED_VIBRATION | USER_LOCKED_SOUND
+ | USER_LOCKED_SHOW_BADGE | USER_LOCKED_ALLOW_BUBBLE);
+ mLogger.clear();
+
+ NotificationChannel parentUpdate = cloneChannel(parent);
+ parentUpdate.setBypassDnd(true);
+ parentUpdate.setLockscreenVisibility(VISIBILITY_SECRET);
+ parentUpdate.setImportance(IMPORTANCE_HIGH);
+ parentUpdate.enableLights(true);
+ parentUpdate.setSound(SOUND_URI, mAudioAttributes);
+ parentUpdate.enableVibration(true);
+ parentUpdate.setShowBadge(false);
+ parentUpdate.setAllowBubbles(true);
+ mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
+ UID_O, /* fromSystemOrSystemUi= */ true);
+
+ NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ "A", /* includeDeleted= */ false);
+ assertThat(updatedChild.canBypassDnd()).isFalse();
+ assertThat(updatedChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_NO_OVERRIDE);
+ assertThat(updatedChild.getImportance()).isEqualTo(IMPORTANCE_DEFAULT);
+ assertThat(updatedChild.shouldShowLights()).isFalse();
+ assertThat(updatedChild.getSound()).isEqualTo(DEFAULT_SOUND_URI);
+ assertThat(updatedChild.shouldVibrate()).isFalse();
+ assertThat(updatedChild.canShowBadge()).isTrue();
+ assertThat(updatedChild.getAllowBubbles()).isEqualTo(DEFAULT_ALLOW_BUBBLE);
+
+ // Verify that only the changes to the parent were logged.
+ assertThat(mLogger.getCalls()).containsExactly(
+ new NotificationChannelLoggerFake.CallRecord(
+ NOTIFICATION_CHANNEL_UPDATED_BY_USER, "messages"));
+ }
+
+ @Test
+ public void testUpdateConversationParent_updatesDemotedConversation() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
+ .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
+ NotificationChannel parent =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
+ convo.setConversationId(parent.getId(), "A");
+ convo.setDemoted(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ convo.getId(), /* includeDeleted= */ false);
+ assertThat(originalChild.shouldVibrate()).isFalse();
+
+ NotificationChannel parentUpdate = cloneChannel(parent);
+ parentUpdate.enableVibration(true);
+ mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
+ UID_O, /* fromSystemOrSystemUi= */ true);
+
+ NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ "A", /* includeDeleted= */ false);
+ assertThat(updatedChild.shouldVibrate()).isTrue();
+ }
+
+ @Test
+ public void testUpdateConversationParent_updatesDeletedConversation() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
+ .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true);
+ NotificationChannel parent =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
+ convo.setConversationId(parent.getId(), "A");
+ mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ mHelper.deleteNotificationChannel(PKG_O, UID_O, "A", UID_O,
+ /* fromSystemOrSystemUi= */ false);
+ assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A",
+ /* includeDeleted= */ false)).isNull();
+
+ NotificationChannel parentUpdate = cloneChannel(parent);
+ parentUpdate.enableVibration(true);
+ mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
+ UID_O, /* fromSystemOrSystemUi= */ true);
+
+ NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ "A", /* includeDeleted= */ true);
+ assertThat(updatedChild.shouldVibrate()).isTrue();
+ }
+
+ @Test
+ public void testUpdateConversationParent_flagOff_doesNotUpdateConversations() {
+ SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver()
+ .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, false);
+ NotificationChannel parent =
+ new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT);
+ convo.setConversationId(parent.getId(), "A");
+ mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true,
+ /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false);
+ NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ convo.getId(), /* includeDeleted= */ false);
+ assertThat(originalChild.shouldVibrate()).isFalse();
+
+ NotificationChannel parentUpdate = cloneChannel(parent);
+ parentUpdate.enableVibration(true);
+ mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true,
+ UID_O, /* fromSystemOrSystemUi= */ true);
+
+ NotificationChannel untouchedChild = mHelper.getNotificationChannel(PKG_O, UID_O,
+ "A", /* includeDeleted= */ false);
+ assertThat(untouchedChild.shouldVibrate()).isFalse();
+ }
+
+ @Test
public void testInvalidMessageSent() {
// create package preferences
mHelper.canShowBadge(PKG_P, UID_P);
@@ -5447,11 +5698,7 @@
clearInvocations(mHandler);
// Note: Creating a NotificationChannel identical to the original is not equals(), because
// of mOriginalImportance. So we create a "true copy" instead.
- Parcel parcel = Parcel.obtain();
- original.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- NotificationChannel same = NotificationChannel.CREATOR.createFromParcel(parcel);
- parcel.recycle();
+ NotificationChannel same = cloneChannel(original);
mHelper.updateNotificationChannel(PKG_P, 0, same, false, 0, false);
@@ -5560,4 +5807,15 @@
assertFalse(isUserSet);
}
+
+ private static NotificationChannel cloneChannel(NotificationChannel original) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return NotificationChannel.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index d179338..870dd48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1332,6 +1332,10 @@
starter.setReason("testNoActivityInfo").setIntent(intent)
.setActivityInfo(null).execute();
verify(starter.mRequest).resolveActivity(any());
+
+ // Also verifies the value of Request#componentSpecified should be true even the
+ // ActivityStarter#setComponentSpecified is not explicitly set.
+ assertTrue(starter.mRequest.componentSpecified);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 7cb7c79d..2b19ad9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -107,6 +107,9 @@
InstrumentationRegistry.getInstrumentation().getContext().getCacheDir();
mFolder = new File(cacheFolder, "launch_params_tests");
deleteRecursively(mFolder);
+ mFolder.mkdir();
+ mUserFolderGetter.apply(TEST_USER_ID).mkdir();
+ mUserFolderGetter.apply(ALTERNATIVE_USER_ID).mkdir();
mDisplayUniqueId = "test:" + sNextUniqueId++;
mTestDisplay = new TestDisplayContent.Builder(mAtm, 1000, 1500)
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 2d8ddfa..a82459f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -64,10 +64,19 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.clearInvocations;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Binder;
+import android.os.DeadObjectException;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Parcel;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.platform.test.annotations.Presubmit;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -87,8 +96,10 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
+import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.NoSuchElementException;
/**
@@ -1404,7 +1415,7 @@
}
@Test
- public void testAddLocalInsetsSourceProvider() {
+ public void testAddLocalInsetsFrameProvider() {
/*
___ rootTask _______________________________________________
| | | |
@@ -1435,19 +1446,20 @@
TYPE_BASE_APPLICATION);
attrs2.setTitle("AppWindow2");
activity2.addWindow(createWindowState(attrs2, activity2));
+ final Binder owner = new Binder();
Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200);
final InsetsFrameProvider provider1 =
- new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
+ new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(genericOverlayInsetsRect1);
final InsetsFrameProvider provider2 =
- new InsetsFrameProvider(null, 2, WindowInsets.Type.systemOverlays())
+ new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(genericOverlayInsetsRect2);
final int sourceId1 = provider1.getId();
final int sourceId2 = provider2.getId();
- rootTask.addLocalInsetsFrameProvider(provider1);
- container.addLocalInsetsFrameProvider(provider2);
+ rootTask.addLocalInsetsFrameProvider(provider1, owner);
+ container.addLocalInsetsFrameProvider(provider2, owner);
InsetsSource genericOverlayInsetsProvider1Source = new InsetsSource(
sourceId1, systemOverlays());
@@ -1479,7 +1491,7 @@
}
@Test
- public void testAddLocalInsetsSourceProvider_sameType_replacesInsets() {
+ public void testAddLocalInsetsFrameProvider_sameType_replacesInsets() {
/*
___ rootTask ________________________________________
| | |
@@ -1494,24 +1506,25 @@
attrs.setTitle("AppWindow0");
activity0.addWindow(createWindowState(attrs, activity0));
+ final Binder owner = new Binder();
final Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
final Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200);
final InsetsFrameProvider provider1 =
- new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
+ new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(genericOverlayInsetsRect1);
final InsetsFrameProvider provider2 =
- new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
+ new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(genericOverlayInsetsRect2);
final int sourceId1 = provider1.getId();
final int sourceId2 = provider2.getId();
- rootTask.addLocalInsetsFrameProvider(provider1);
+ rootTask.addLocalInsetsFrameProvider(provider1, owner);
activity0.forAllWindows(window -> {
assertEquals(genericOverlayInsetsRect1,
window.getInsetsState().peekSource(sourceId1).getFrame());
}, true);
- rootTask.addLocalInsetsFrameProvider(provider2);
+ rootTask.addLocalInsetsFrameProvider(provider2, owner);
activity0.forAllWindows(window -> {
assertEquals(genericOverlayInsetsRect2,
@@ -1520,7 +1533,7 @@
}
@Test
- public void testRemoveLocalInsetsSourceProvider() {
+ public void testRemoveLocalInsetsFrameProvider() {
/*
___ rootTask _______________________________________________
| | | |
@@ -1554,21 +1567,22 @@
activity2.addWindow(createWindowState(attrs2, activity2));
+ final Binder owner = new Binder();
final Rect navigationBarInsetsRect1 = new Rect(0, 200, 1080, 700);
final Rect navigationBarInsetsRect2 = new Rect(0, 0, 1080, 200);
final InsetsFrameProvider provider1 =
- new InsetsFrameProvider(null, 1, WindowInsets.Type.systemOverlays())
+ new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(navigationBarInsetsRect1);
final InsetsFrameProvider provider2 =
- new InsetsFrameProvider(null, 2, WindowInsets.Type.systemOverlays())
+ new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays())
.setArbitraryRectangle(navigationBarInsetsRect2);
final int sourceId1 = provider1.getId();
final int sourceId2 = provider2.getId();
- rootTask.addLocalInsetsFrameProvider(provider1);
- container.addLocalInsetsFrameProvider(provider2);
+ rootTask.addLocalInsetsFrameProvider(provider1, owner);
+ container.addLocalInsetsFrameProvider(provider2, owner);
mDisplayContent.getInsetsStateController().onPostLayout();
- rootTask.removeLocalInsetsFrameProvider(provider1);
+ rootTask.removeLocalInsetsFrameProvider(provider1, owner);
mDisplayContent.getInsetsStateController().onPostLayout();
activity0.forAllWindows(window -> {
@@ -1593,6 +1607,67 @@
}, true);
}
+ @Test
+ public void testAddLocalInsetsFrameProvider_ownerDiesAfterAdding() {
+ final Task task = createTask(mDisplayContent);
+ final TestBinder owner = new TestBinder();
+ final InsetsFrameProvider provider =
+ new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
+ .setArbitraryRectangle(new Rect());
+ task.addLocalInsetsFrameProvider(provider, owner);
+
+ assertTrue("The death recipient must exist.", owner.hasDeathRecipient());
+ assertTrue("The source must be added.", hasLocalSource(task, provider.getId()));
+
+ // The owner dies after adding the source.
+ owner.die();
+
+ assertFalse("The death recipient must be removed.", owner.hasDeathRecipient());
+ assertFalse("The source must be removed.", hasLocalSource(task, provider.getId()));
+ }
+
+ @Test
+ public void testAddLocalInsetsFrameProvider_ownerDiesBeforeAdding() {
+ final Task task = createTask(mDisplayContent);
+ final TestBinder owner = new TestBinder();
+
+ // The owner dies before adding the source.
+ owner.die();
+
+ final InsetsFrameProvider provider =
+ new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
+ .setArbitraryRectangle(new Rect());
+ task.addLocalInsetsFrameProvider(provider, owner);
+
+ assertFalse("The death recipient must not exist.", owner.hasDeathRecipient());
+ assertFalse("The source must not be added.", hasLocalSource(task, provider.getId()));
+ }
+
+ @Test
+ public void testRemoveLocalInsetsFrameProvider_removeDeathRecipient() {
+ final Task task = createTask(mDisplayContent);
+ final TestBinder owner = new TestBinder();
+ final InsetsFrameProvider provider =
+ new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
+ .setArbitraryRectangle(new Rect());
+ task.addLocalInsetsFrameProvider(provider, owner);
+
+ assertTrue("The death recipient must exist.", owner.hasDeathRecipient());
+ assertTrue("The source must be added.", hasLocalSource(task, provider.getId()));
+
+ task.removeLocalInsetsFrameProvider(provider, owner);
+
+ assertFalse("The death recipient must be removed.", owner.hasDeathRecipient());
+ assertFalse("The source must be removed.", hasLocalSource(task, provider.getId()));
+ }
+
+ private static boolean hasLocalSource(WindowContainer container, int sourceId) {
+ if (container.mLocalInsetsSources == null) {
+ return false;
+ }
+ return container.mLocalInsetsSources.contains(sourceId);
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
@@ -1797,4 +1872,82 @@
mIsVisibleRequested = isVisibleRequested;
}
}
+
+ private static class TestBinder implements IBinder {
+
+ private boolean mDead;
+ private final ArrayList<IBinder.DeathRecipient> mDeathRecipients = new ArrayList<>();
+
+ public void die() {
+ mDead = true;
+ for (int i = mDeathRecipients.size() - 1; i >= 0; i--) {
+ final DeathRecipient recipient = mDeathRecipients.get(i);
+ recipient.binderDied(this);
+ }
+ }
+
+ public boolean hasDeathRecipient() {
+ return !mDeathRecipients.isEmpty();
+ }
+
+ @Override
+ public void linkToDeath(@NonNull DeathRecipient recipient, int flags)
+ throws RemoteException {
+ if (mDead) {
+ throw new DeadObjectException();
+ }
+ mDeathRecipients.add(recipient);
+ }
+
+ @Override
+ public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
+ final boolean successes = mDeathRecipients.remove(recipient);
+ if (successes || mDead) {
+ return successes;
+ }
+ throw new NoSuchElementException("Given recipient has not been registered.");
+ }
+
+ @Override
+ public boolean isBinderAlive() {
+ return !mDead;
+ }
+
+ @Override
+ public boolean pingBinder() {
+ return !mDead;
+ }
+
+ @Nullable
+ @Override
+ public String getInterfaceDescriptor() throws RemoteException {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public IInterface queryLocalInterface(@NonNull String descriptor) {
+ return null;
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @Nullable String[] args)
+ throws RemoteException { }
+
+ @Override
+ public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args)
+ throws RemoteException { }
+
+ @Override
+ public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
+ @Nullable FileDescriptor err, @NonNull String[] args,
+ @Nullable ShellCallback shellCallback,
+ @NonNull ResultReceiver resultReceiver) throws RemoteException { }
+
+ @Override
+ public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
+ throws RemoteException {
+ return false;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 5c1b262..45331f7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -1036,7 +1036,7 @@
private boolean setupLetterboxConfigurationWithBackgroundType(
@LetterboxConfiguration.LetterboxBackgroundType int letterboxBackgroundType) {
- mWm.mLetterboxConfiguration.setLetterboxBackgroundType(letterboxBackgroundType);
+ mWm.mLetterboxConfiguration.setLetterboxBackgroundTypeOverride(letterboxBackgroundType);
return mWm.isLetterboxBackgroundMultiColored();
}
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index d8f63df..a2fbc95 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -257,6 +257,9 @@
// Updated based on the accessNetworkTechnology
private boolean mIsUsingCarrierAggregation;
+ // Set to {@code true} when network is a non-terrestrial network.
+ private boolean mIsNonTerrestrialNetwork;
+
/**
* @param domain Network domain. Must be a {@link Domain}. For transport type
* {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}.
@@ -280,6 +283,7 @@
* @param rplmn the registered plmn or the last plmn for attempted registration if reg failed.
* @param voiceSpecificInfo Voice specific registration information.
* @param dataSpecificInfo Data specific registration information.
+ * @param isNonTerrestrialNetwork {@code true} if network is a non-terrestrial network.
*/
private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
@RegistrationState int registrationState,
@@ -287,7 +291,8 @@
boolean emergencyOnly, @Nullable @ServiceType List<Integer> availableServices,
@Nullable CellIdentity cellIdentity, @Nullable String rplmn,
@Nullable VoiceSpecificRegistrationInfo voiceSpecificInfo,
- @Nullable DataSpecificRegistrationInfo dataSpecificInfo) {
+ @Nullable DataSpecificRegistrationInfo dataSpecificInfo,
+ boolean isNonTerrestrialNetwork) {
mDomain = domain;
mTransportType = transportType;
mRegistrationState = registrationState;
@@ -304,6 +309,7 @@
mRplmn = rplmn;
mVoiceSpecificInfo = voiceSpecificInfo;
mDataSpecificInfo = dataSpecificInfo;
+ mIsNonTerrestrialNetwork = isNonTerrestrialNetwork;
updateNrState();
}
@@ -322,7 +328,7 @@
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
emergencyOnly, availableServices, cellIdentity, rplmn,
new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
- systemIsInPrl, defaultRoamingIndicator), null);
+ systemIsInPrl, defaultRoamingIndicator), null, false);
}
/**
@@ -344,7 +350,7 @@
.setNrAvailable(isNrAvailable)
.setEnDcAvailable(isEndcAvailable)
.setVopsSupportInfo(vopsSupportInfo)
- .build());
+ .build(), false);
}
private NetworkRegistrationInfo(Parcel source) {
@@ -366,6 +372,7 @@
mNrState = source.readInt();
mRplmn = source.readString();
mIsUsingCarrierAggregation = source.readBoolean();
+ mIsNonTerrestrialNetwork = source.readBoolean();
}
/**
@@ -382,6 +389,7 @@
mRoamingType = nri.mRoamingType;
mAccessNetworkTechnology = nri.mAccessNetworkTechnology;
mIsUsingCarrierAggregation = nri.mIsUsingCarrierAggregation;
+ mIsNonTerrestrialNetwork = nri.mIsNonTerrestrialNetwork;
mRejectCause = nri.mRejectCause;
mEmergencyOnly = nri.mEmergencyOnly;
mAvailableServices = new ArrayList<>(nri.mAvailableServices);
@@ -658,6 +666,26 @@
}
/**
+ * Set whether the network is a non-terrestrial network.
+ *
+ * @param isNonTerrestrialNetwork {@code true} if network is a non-terrestrial network
+ * else {@code false}.
+ * @hide
+ */
+ public void setIsNonTerrestrialNetwork(boolean isNonTerrestrialNetwork) {
+ mIsNonTerrestrialNetwork = isNonTerrestrialNetwork;
+ }
+
+ /**
+ * Get whether the network is a non-terrestrial network.
+ *
+ * @return {@code true} if network is a non-terrestrial network else {@code false}.
+ */
+ public boolean isNonTerrestrialNetwork() {
+ return mIsNonTerrestrialNetwork;
+ }
+
+ /**
* @hide
*/
@Nullable
@@ -769,6 +797,7 @@
? nrStateToString(mNrState) : "****")
.append(" rRplmn=").append(mRplmn)
.append(" isUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
+ .append(" isNonTerrestrialNetwork=").append(mIsNonTerrestrialNetwork)
.append("}").toString();
}
@@ -777,7 +806,7 @@
return Objects.hash(mDomain, mTransportType, mRegistrationState, mNetworkRegistrationState,
mRoamingType, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly,
mAvailableServices, mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState,
- mRplmn, mIsUsingCarrierAggregation);
+ mRplmn, mIsUsingCarrierAggregation, mIsNonTerrestrialNetwork);
}
@Override
@@ -803,7 +832,8 @@
&& Objects.equals(mVoiceSpecificInfo, other.mVoiceSpecificInfo)
&& Objects.equals(mDataSpecificInfo, other.mDataSpecificInfo)
&& TextUtils.equals(mRplmn, other.mRplmn)
- && mNrState == other.mNrState;
+ && mNrState == other.mNrState
+ && mIsNonTerrestrialNetwork == other.mIsNonTerrestrialNetwork;
}
/**
@@ -827,6 +857,7 @@
dest.writeInt(mNrState);
dest.writeString(mRplmn);
dest.writeBoolean(mIsUsingCarrierAggregation);
+ dest.writeBoolean(mIsNonTerrestrialNetwork);
}
/**
@@ -936,6 +967,8 @@
@Nullable
private VoiceSpecificRegistrationInfo mVoiceSpecificRegistrationInfo;
+ private boolean mIsNonTerrestrialNetwork;
+
/**
* Default constructor for Builder.
*/
@@ -964,6 +997,7 @@
mVoiceSpecificRegistrationInfo = new VoiceSpecificRegistrationInfo(
nri.mVoiceSpecificInfo);
}
+ mIsNonTerrestrialNetwork = nri.mIsNonTerrestrialNetwork;
}
/**
@@ -1111,6 +1145,18 @@
}
/**
+ * Set whether the network is a non-terrestrial network.
+ *
+ * @param isNonTerrestrialNetwork {@code true} if network is a non-terrestrial network
+ * else {@code false}.
+ * @return The builder.
+ */
+ public @NonNull Builder setIsNonTerrestrialNetwork(boolean isNonTerrestrialNetwork) {
+ mIsNonTerrestrialNetwork = isNonTerrestrialNetwork;
+ return this;
+ }
+
+ /**
* Build the NetworkRegistrationInfo.
* @return the NetworkRegistrationInfo object.
* @hide
@@ -1120,7 +1166,7 @@
return new NetworkRegistrationInfo(mDomain, mTransportType, mNetworkRegistrationState,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
mCellIdentity, mRplmn, mVoiceSpecificRegistrationInfo,
- mDataSpecificRegistrationInfo);
+ mDataSpecificRegistrationInfo, mIsNonTerrestrialNetwork);
}
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 523d0b0..5b8848c 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -2250,4 +2250,18 @@
return false;
}
}
+
+ /**
+ * Get whether device is connected to a non-terrestrial network.
+ *
+ * @return {@code true} if device is connected to a non-terrestrial network else {@code false}.
+ */
+ public boolean isUsingNonTerrestrialNetwork() {
+ synchronized (mNetworkRegistrationInfos) {
+ for (NetworkRegistrationInfo nri : mNetworkRegistrationInfos) {
+ if (nri.isNonTerrestrialNetwork()) return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
index 48d050c..bb0d30a 100644
--- a/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
+++ b/tests/ChoreographerTests/src/main/java/android/view/choreographertests/AttachedChoreographerTest.java
@@ -22,9 +22,9 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.Manifest;
-import android.app.compat.CompatChanges;
import android.hardware.display.DisplayManager;
import android.os.Looper;
import android.support.test.uiautomator.UiDevice;
@@ -34,6 +34,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.WindowManager;
import androidx.lifecycle.Lifecycle;
import androidx.test.core.app.ActivityScenario;
@@ -52,7 +53,7 @@
public class AttachedChoreographerTest {
private static final String TAG = "AttachedChoreographerTest";
private static final long DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE_CHANGEID = 170503758;
- private static final long THRESHOLD_MS = 10;
+ private static final long THRESHOLD_MS = 4;
private static final int FRAME_ITERATIONS = 21;
private static final int CALLBACK_MISSED_THRESHOLD = 2;
@@ -66,7 +67,7 @@
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private Choreographer mChoreographer;
- private boolean mIsFirstCallback = true;
+ private long mExpectedPresentTime;
private int mCallbackMissedCounter = 0;
@Before
@@ -74,6 +75,13 @@
mScenario = ActivityScenario.launch(GraphicsActivity.class);
mScenario.moveToState(Lifecycle.State.CREATED);
mScenario.onActivity(activity -> {
+ // Lock the display frame rate. This will not allow SurfaceFlinger to use the frame rate
+ // override feature that throttles down the global choreographer for this test.
+ float refreshRate = activity.getDisplay().getMode().getRefreshRate();
+ WindowManager.LayoutParams attrs = activity.getWindow().getAttributes();
+ attrs.preferredRefreshRate = refreshRate;
+ activity.getWindow().setAttributes(attrs);
+
mSurfaceView = activity.findViewById(R.id.surface);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
@@ -95,6 +103,12 @@
});
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+ // TODO(b/290634611): clean this up once SF new front end is enabled by default
+ boolean sfNewFeEnabled = uiDevice.executeShellCommand("dumpsys SurfaceFlinger")
+ .indexOf("SurfaceFlinger New Frontend Enabled:true") != -1;
+ assumeTrue(sfNewFeEnabled);
+
uiDevice.wakeUp();
uiDevice.executeShellCommand("wm dismiss-keyguard");
mScenario.moveToState(Lifecycle.State.RESUMED);
@@ -112,18 +126,16 @@
mDisplayManager.setRefreshRateSwitchingType(
DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY);
mDisplayManager.setShouldAlwaysRespectAppRequestedMode(true);
- boolean changeIsEnabled =
- CompatChanges.isChangeEnabled(
- DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE_CHANGEID);
- Log.i(TAG, "DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE_CHANGE_ID is "
- + (changeIsEnabled ? "enabled" : "disabled"));
});
}
@After
public void tearDown() {
- mDisplayManager.setRefreshRateSwitchingType(mInitialMatchContentFrameRate);
- mDisplayManager.setShouldAlwaysRespectAppRequestedMode(false);
+ if (mDisplayManager != null) {
+ mDisplayManager.setRefreshRateSwitchingType(mInitialMatchContentFrameRate);
+ mDisplayManager.setShouldAlwaysRespectAppRequestedMode(false);
+ }
+
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
}
@@ -407,18 +419,141 @@
}
}
+ @Test
+ public void testChoreographerAttachedAfterSetFrameRate() {
+ Log.i(TAG, "adyabr: starting testChoreographerAttachedAfterSetFrameRate");
+
+ class TransactionGenerator implements SurfaceControl.TransactionCommittedListener {
+ private SurfaceControl mSc;
+ private int mFrame;
+ private static final int NUM_FRAMES = 50;
+ private final CountDownLatch mCompleteLatch = new CountDownLatch(1);
+
+ TransactionGenerator(SurfaceControl sc) {
+ mSc = sc;
+
+ }
+
+ @Override
+ public void onTransactionCommitted() {
+ mFrame++;
+ if (mFrame >= NUM_FRAMES) {
+ mCompleteLatch.countDown();
+ return;
+ }
+
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ transaction.setAlpha(mSc, 1.0f / mFrame)
+ .addTransactionCommittedListener(Runnable::run, this)
+ .apply();
+
+ }
+
+ public void startAndWaitForCompletion() {
+ onTransactionCommitted();
+ if (waitForCountDown(mCompleteLatch, /* timeoutInSeconds */ 10L)) {
+ fail("failed to send new transactions");
+ }
+ }
+ }
+
+
+ for (int divisor : new int[]{2, 3}) {
+ CountDownLatch choreographerLatch = new CountDownLatch(1);
+ mScenario.onActivity(activity -> {
+ if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
+ fail("Unable to create surface within 1 Second");
+ }
+
+ SurfaceControl sc = mSurfaceView.getSurfaceControl();
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ float displayRefreshRate = activity.getDisplay().getMode().getRefreshRate();
+ float fps = displayRefreshRate / divisor;
+ long callbackDurationMs = Math.round(1000 / fps);
+ mCallbackMissedCounter = 0;
+ transaction.setFrameRate(sc, fps, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)
+ .apply();
+
+
+ new TransactionGenerator(sc).startAndWaitForCompletion();
+
+ Choreographer choreographer = sc.getChoreographer();
+ verifyVsyncCallbacks(choreographer, callbackDurationMs,
+ choreographerLatch, FRAME_ITERATIONS);
+ });
+ // wait for the previous callbacks to finish before moving to the next divisor
+ if (waitForCountDown(choreographerLatch, /* timeoutInSeconds */ 5L)) {
+ fail("Test not finished in 5 Seconds");
+ }
+ }
+ }
+
+ @Test
+ public void testChoreographerNonDivisorFixedSourceRefreshRate() {
+ CountDownLatch continueLatch = new CountDownLatch(1);
+ mScenario.onActivity(activity -> {
+ if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
+ fail("Unable to create surface within 1 Second");
+ }
+ SurfaceControl sc = mSurfaceView.getSurfaceControl();
+ Choreographer choreographer = sc.getChoreographer();
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ float displayRefreshRate = activity.getDisplay().getMode().getRefreshRate();
+ float fps = 61.7f; // hopefully not a divisor
+ long callbackDurationMs = Math.round(1000 / displayRefreshRate);
+ mCallbackMissedCounter = 0;
+ transaction.setFrameRate(sc, fps, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE)
+ .addTransactionCommittedListener(Runnable::run,
+ () -> verifyVsyncCallbacks(choreographer,
+ callbackDurationMs, continueLatch, FRAME_ITERATIONS))
+ .apply();
+ });
+ // wait for the previous callbacks to finish before moving to the next divisor
+ if (waitForCountDown(continueLatch, /* timeoutInSeconds */ 5L)) {
+ fail("Test not finished in 5 Seconds");
+ }
+ }
+
+ @Test
+ public void testChoreographerNonDivisorRefreshRate() {
+ CountDownLatch continueLatch = new CountDownLatch(1);
+ mScenario.onActivity(activity -> {
+ if (waitForCountDown(mSurfaceCreationCountDown, /* timeoutInSeconds */ 1L)) {
+ fail("Unable to create surface within 1 Second");
+ }
+ SurfaceControl sc = mSurfaceView.getSurfaceControl();
+ Choreographer choreographer = sc.getChoreographer();
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ float displayRefreshRate = activity.getDisplay().getMode().getRefreshRate();
+ float fps = 61.7f; // hopefully not a divisor
+ float expectedFps = displayRefreshRate / Math.round(displayRefreshRate / fps);
+ long callbackDurationMs = Math.round(1000 / expectedFps);
+ mCallbackMissedCounter = 0;
+ transaction.setFrameRate(sc, fps, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .addTransactionCommittedListener(Runnable::run,
+ () -> verifyVsyncCallbacks(choreographer,
+ callbackDurationMs, continueLatch, FRAME_ITERATIONS))
+ .apply();
+ });
+ // wait for the previous callbacks to finish before moving to the next divisor
+ if (waitForCountDown(continueLatch, /* timeoutInSeconds */ 5L)) {
+ fail("Test not finished in 5 Seconds");
+ }
+ }
+
private void verifyVsyncCallbacks(Choreographer choreographer, long callbackDurationMs,
CountDownLatch continueLatch, int frameCount) {
- long callbackRequestedTimeNs = System.nanoTime();
choreographer.postVsyncCallback(frameData -> {
+ long expectedPresentTime =
+ frameData.getPreferredFrameTimeline().getExpectedPresentationTimeNanos();
if (frameCount > 0) {
- if (!mIsFirstCallback) {
- // Skip the first callback as it takes 1 frame
- // to reflect the new refresh rate
- long callbackDurationDiffMs = getCallbackDurationDiffInMs(
- frameData.getFrameTimeNanos(),
- callbackRequestedTimeNs, callbackDurationMs);
- if (callbackDurationDiffMs < 0 || callbackDurationDiffMs > THRESHOLD_MS) {
+ if (mExpectedPresentTime > 0) {
+ long callbackDurationDiffMs =
+ TimeUnit.NANOSECONDS.toMillis(
+ expectedPresentTime - mExpectedPresentTime);
+ if (callbackDurationDiffMs < 0
+ || Math.abs(callbackDurationMs - callbackDurationDiffMs)
+ > THRESHOLD_MS) {
mCallbackMissedCounter++;
Log.e(TAG, "Frame #" + Math.abs(frameCount - FRAME_ITERATIONS)
+ " vsync callback failed, expected callback in "
@@ -427,25 +562,19 @@
+ " but actual duration difference is " + callbackDurationDiffMs);
}
}
- mIsFirstCallback = false;
+ mExpectedPresentTime = expectedPresentTime;
verifyVsyncCallbacks(choreographer, callbackDurationMs,
continueLatch, frameCount - 1);
} else {
- assertTrue("Missed timeline for " + mCallbackMissedCounter + " callbacks, while "
- + CALLBACK_MISSED_THRESHOLD + " missed callbacks are allowed",
+ assertTrue("Missed timeline for " + mCallbackMissedCounter
+ + " callbacks, while " + CALLBACK_MISSED_THRESHOLD
+ + " missed callbacks are allowed",
mCallbackMissedCounter <= CALLBACK_MISSED_THRESHOLD);
continueLatch.countDown();
}
});
}
- private long getCallbackDurationDiffInMs(long callbackTimeNs, long requestedTimeNs,
- long expectedCallbackMs) {
- long actualTimeMs = TimeUnit.NANOSECONDS.toMillis(callbackTimeNs)
- - TimeUnit.NANOSECONDS.toMillis(requestedTimeNs);
- return Math.abs(expectedCallbackMs - actualTimeMs);
- }
-
private boolean waitForCountDown(CountDownLatch countDownLatch, long timeoutInSeconds) {
try {
return !countDownLatch.await(timeoutInSeconds, TimeUnit.SECONDS);
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 37b529b..72b5159 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -68,6 +68,13 @@
srcs: ["src/**/rotation/*.kt"],
}
+filegroup {
+ name: "FlickerServiceTests-src",
+ srcs: [
+ "src/com/android/server/wm/flicker/service/**/*.kt",
+ ],
+}
+
java_defaults {
name: "FlickerTestsDefault",
manifest: "manifests/AndroidManifest.xml",
@@ -110,6 +117,7 @@
":FlickerTestsQuickswitch-src",
":FlickerTestsRotation-src",
":FlickerTestsNotification-src",
+ ":FlickerServiceTests-src",
],
}
@@ -194,6 +202,18 @@
],
}
+android_test {
+ name: "FlickerServiceTests",
+ defaults: ["FlickerTestsDefault"],
+ additional_manifests: ["manifests/AndroidManifestService.xml"],
+ package_name: "com.android.server.wm.flicker.service",
+ instrumentation_target_package: "com.android.server.wm.flicker.service",
+ srcs: [
+ ":FlickerTestsBase-src",
+ ":FlickerServiceTests-src",
+ ],
+}
+
java_library {
name: "wm-flicker-common-assertions",
platform_apis: true,
diff --git a/tests/FlickerTests/AndroidTestTemplate.xml b/tests/FlickerTests/AndroidTestTemplate.xml
index ed63ec0..44a8245 100644
--- a/tests/FlickerTests/AndroidTestTemplate.xml
+++ b/tests/FlickerTests/AndroidTestTemplate.xml
@@ -87,6 +87,8 @@
value="/data/user/0/com.android.server.wm.flicker.rotation/files"/>
<option name="directory-keys"
value="/data/user/0/com.android.server.wm.flicker.notification/files"/>
+ <option name="directory-keys"
+ value="/data/user/0/com.android.server.wm.flicker.service/files"/>
<option name="collect-on-run-ended-only" value="true"/>
<option name="clean-up" value="true"/>
</metrics_collector>
diff --git a/tests/FlickerTests/manifests/AndroidManifestService.xml b/tests/FlickerTests/manifests/AndroidManifestService.xml
new file mode 100644
index 0000000..3a7bc509
--- /dev/null
+++ b/tests/FlickerTests/manifests/AndroidManifestService.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.wm.flicker.service">
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.wm.flicker.service"
+ android:label="WindowManager Flicker Service Tests">
+ </instrumentation>
+</manifest>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
new file mode 100644
index 0000000..144a7312
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.activityembedding
+
+import android.platform.test.annotations.Presubmit
+import android.tools.common.datatypes.Rect
+import android.tools.common.flicker.subject.region.RegionSubject
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching a trampoline activity and resulting in a split state.
+ *
+ * Setup: Launch Activity A in fullscreen.
+ *
+ * Transitions: From A launch a trampoline Activity T, T launches secondary Activity B and finishes
+ * itself, end up in split A|B.
+ *
+ * To run this test: `atest FlickerTests:OpenTrampolineActivityTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class OpenTrampolineActivityTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBase(flicker) {
+ override val transition: FlickerBuilder.() -> Unit = {
+ setup {
+ tapl.setExpectedRotationCheckEnabled(false)
+ testApp.launchViaIntent(wmHelper)
+ startDisplayBounds =
+ wmHelper.currentState.layerState.physicalDisplayBounds
+ ?: error("Can't get display bounds")
+ }
+ transitions { testApp.launchTrampolineActivity(wmHelper) }
+ teardown {
+ tapl.goHome()
+ testApp.exit(wmHelper)
+ }
+ }
+
+ /** Assert the background animation layer is never visible during bounds change transition. */
+ @Presubmit
+ @Test
+ fun backgroundLayerNeverVisible() {
+ val backgroundColorLayer = ComponentNameMatcher("", "Animation Background")
+ flicker.assertLayers { isInvisible(backgroundColorLayer) }
+ }
+
+ /** Trampoline activity should finish itself before the end of this test. */
+ @Presubmit
+ @Test
+ fun trampolineActivityFinishes() {
+ flicker.assertWmEnd {
+ notContains(ActivityEmbeddingAppHelper.TRAMPOLINE_ACTIVITY_COMPONENT)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun trampolineLayerNeverVisible() {
+ flicker.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.TRAMPOLINE_ACTIVITY_COMPONENT)
+ }
+ }
+
+ /** Main activity is always visible throughout this test. */
+ @Presubmit
+ @Test
+ fun mainActivityWindowAlwaysVisible() {
+ flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
+ }
+
+ // TODO(b/289140963): After this is fixed, assert the main Activity window is visible
+ // throughout the test instead.
+ /** Main activity layer is visible before and after the transition. */
+ @Presubmit
+ @Test
+ fun mainActivityLayerAlwaysVisible() {
+ flicker.assertLayersStart { isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
+ flicker.assertLayersEnd { isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
+ }
+
+ /** Secondary activity is launched from the trampoline activity. */
+ @Presubmit
+ @Test
+ fun secondaryActivityWindowLaunchedFromTrampoline() {
+ flicker.assertWm {
+ notContains(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isAppWindowInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ /** Secondary activity is launched from the trampoline activity. */
+ @Presubmit
+ @Test
+ fun secondaryActivityLayerLaunchedFromTrampoline() {
+ flicker.assertLayers {
+ isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ }
+
+ /** Main activity should go from fullscreen to being a split with secondary activity. */
+ @Presubmit
+ @Test
+ fun mainActivityWindowGoesFromFullscreenToSplit() {
+ flicker.assertWm {
+ this.invoke("mainActivityStartsInFullscreen") {
+ it.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .coversExactly(startDisplayBounds)
+ }
+ // Begin of transition.
+ .then()
+ .isAppWindowInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .invoke("mainAndSecondaryInSplit") {
+ val mainActivityRegion =
+ RegionSubject(
+ it.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .region,
+ it.timestamp
+ )
+ val secondaryActivityRegion =
+ RegionSubject(
+ it.visibleRegion(
+ ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT
+ )
+ .region,
+ it.timestamp
+ )
+ check { "height" }
+ .that(mainActivityRegion.region.height)
+ .isEqual(secondaryActivityRegion.region.height)
+ check { "width" }
+ .that(mainActivityRegion.region.width)
+ .isEqual(secondaryActivityRegion.region.width)
+ mainActivityRegion
+ .plus(secondaryActivityRegion.region)
+ .coversExactly(startDisplayBounds)
+ }
+ }
+ }
+
+ /** Main activity should go from fullscreen to being a split with secondary activity. */
+ @Presubmit
+ @Test
+ fun mainActivityLayerGoesFromFullscreenToSplit() {
+ flicker.assertLayers {
+ this.invoke("mainActivityStartsInFullscreen") {
+ it.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ .coversExactly(startDisplayBounds)
+ }
+ .then()
+ .isInvisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ .then()
+ .isVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ }
+ flicker.assertLayersEnd {
+ val leftLayerRegion = visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+ val rightLayerRegion =
+ visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+ // Compare dimensions of two splits, given we're using default split attributes,
+ // both activities take up the same visible size on the display.
+ check { "height" }
+ .that(leftLayerRegion.region.height)
+ .isEqual(rightLayerRegion.region.height)
+ check { "width" }
+ .that(leftLayerRegion.region.width)
+ .isEqual(rightLayerRegion.region.width)
+ leftLayerRegion.notOverlaps(rightLayerRegion.region)
+ // Layers of two activities sum to be fullscreen size on display.
+ leftLayerRegion.plus(rightLayerRegion.region).coversExactly(startDisplayBounds)
+ }
+ }
+
+ companion object {
+ /** {@inheritDoc} */
+ private var startDisplayBounds = Rect.EMPTY
+
+ /**
+ * Creates the test configurations.
+ *
+ * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+ * navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index dbbc771..71db76e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -22,7 +22,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -71,12 +70,11 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@FlickerServiceCompatible
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseAppBackButtonTest(flicker: LegacyFlickerTest) : CloseAppTransition(flicker) {
+class CloseAppBackButtonTest(flicker: LegacyFlickerTest) : CloseAppTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTestCfArm.kt
deleted file mode 100644
index 566f393..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTestCfArm.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.close
-
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@FlickerServiceCompatible
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppBackButtonTestCfArm(flicker: LegacyFlickerTest) : CloseAppBackButtonTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index ed930fc..8dd7e65 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -22,7 +22,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -71,12 +70,11 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@FlickerServiceCompatible
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseAppHomeButtonTest(flicker: LegacyFlickerTest) : CloseAppTransition(flicker) {
+class CloseAppHomeButtonTest(flicker: LegacyFlickerTest) : CloseAppTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTestCfArm.kt
deleted file mode 100644
index 49ed183..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTestCfArm.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.close
-
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@FlickerServiceCompatible
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppHomeButtonTestCfArm(flicker: LegacyFlickerTest) : CloseAppHomeButtonTest(flicker) {
- companion object {
- /** Creates the test configurations. */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index ced7a1e..a72ec1e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -77,6 +77,25 @@
}
/**
+ * Clicks the button to launch the trampoline activity, which should launch the secondary
+ * activity and finish itself.
+ */
+ fun launchTrampolineActivity(wmHelper: WindowManagerStateHelper) {
+ val launchButton =
+ uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "launch_trampoline_button")),
+ FIND_TIMEOUT
+ )
+ require(launchButton != null) { "Can't find launch trampoline activity button on screen." }
+ launchButton.click()
+ wmHelper
+ .StateSyncBuilder()
+ .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+ .withActivityRemoved(TRAMPOLINE_ACTIVITY_COMPONENT)
+ .waitForAndVerify()
+ }
+
+ /**
* Clicks the button to finishes the secondary activity launched through
* [launchSecondaryActivity], waits for the main activity to resume.
*/
@@ -197,6 +216,9 @@
ActivityOptions.ActivityEmbedding.PlaceholderSecondaryActivity.COMPONENT
.toFlickerComponent()
+ val TRAMPOLINE_ACTIVITY_COMPONENT =
+ ActivityOptions.ActivityEmbedding.TrampolineActivity.COMPONENT.toFlickerComponent()
+
@JvmStatic
fun getWindowExtensions(): WindowExtensions? {
try {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index c975a50..24e231c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -250,13 +250,10 @@
waitConditions = arrayOf(ConditionsFactory.hasPipWindow())
)
- val windowRegion = wmHelper.getWindowRegion(this)
-
wmHelper
.StateSyncBuilder()
.withWindowSurfaceAppeared(this)
.withPipShown()
- .withSurfaceVisibleRegion(this, windowRegion)
.waitForAndVerify()
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index 98446c1..47a1619 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeEditorPopupDialogAppHelper
import org.junit.FixMethodOrder
@@ -33,11 +32,10 @@
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeOnDismissPopupDialogTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class CloseImeOnDismissPopupDialogTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val imeTestApp = ImeEditorPopupDialogAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTestCfArm.kt
deleted file mode 100644
index d87a1da..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTestCfArm.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeOnDismissPopupDialogTestCfArm(flicker: LegacyFlickerTest) :
- CloseImeOnDismissPopupDialogTest(flicker) {
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index b995d3df..48c54ea 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
import org.junit.FixMethodOrder
@@ -37,11 +36,10 @@
* Test IME window closing to home transitions. To run this test: `atest
* FlickerTests:CloseImeWindowToHomeTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeOnGoHomeTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class CloseImeOnGoHomeTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTestCfArm.kt
deleted file mode 100644
index 3b5bfa9..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTestCfArm.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeOnGoHomeTestCfArm(flicker: LegacyFlickerTest) : CloseImeOnGoHomeTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index 765bb4c..31d5d7f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import org.junit.FixMethodOrder
@@ -45,11 +44,10 @@
*
* To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToHomeTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeShownOnAppStartOnGoHomeTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class CloseImeShownOnAppStartOnGoHomeTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTestCfArm.kt
deleted file mode 100644
index 58411cc..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeShownOnAppStartOnGoHomeTestCfArm(flicker: LegacyFlickerTest) :
- CloseImeShownOnAppStartOnGoHomeTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index c87217b..180ae5d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import org.junit.FixMethodOrder
@@ -45,12 +44,10 @@
*
* To run this test: `atest FlickerTests:CloseImeAutoOpenWindowToAppTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeShownOnAppStartToAppOnPressBackTest(flicker: LegacyFlickerTest) :
- BaseTest(flicker) {
+class CloseImeShownOnAppStartToAppOnPressBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTestCfArm.kt
deleted file mode 100644
index 41b06c0..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeShownOnAppStartToAppOnPressBackTestCfArm(flicker: LegacyFlickerTest) :
- CloseImeShownOnAppStartToAppOnPressBackTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index c74870b..a0573b7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
@@ -38,11 +37,10 @@
* Test IME window closing back to app window transitions. To run this test: `atest
* FlickerTests:CloseImeWindowToAppTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeToAppOnPressBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class CloseImeToAppOnPressBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTestCfArm.kt
deleted file mode 100644
index 104af22..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeToAppOnPressBackTestCfArm(flicker: LegacyFlickerTest) :
- CloseImeToAppOnPressBackTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index 21fd590..99858ce 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -40,11 +39,10 @@
*
* To run this test: `atest FlickerTests:OpenImeWindowAndCloseTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeToHomeOnFinishActivityTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class CloseImeToHomeOnFinishActivityTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val simpleApp = SimpleAppHelper(instrumentation)
private val testApp = ImeAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTestCfArm.kt
deleted file mode 100644
index 0e18385..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class CloseImeToHomeOnFinishActivityTestCfArm(flicker: LegacyFlickerTest) :
- CloseImeToHomeOnFinishActivityTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppCfArmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppCfArmTest.kt
deleted file mode 100644
index db80001..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppCfArmTest.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeOnAppStartWhenLaunchingAppCfArmTest(flicker: LegacyFlickerTest) :
- ShowImeOnAppStartWhenLaunchingAppTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
index 52e9652..c1db423 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
@@ -25,7 +25,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import com.android.server.wm.flicker.helpers.setRotation
@@ -41,11 +40,10 @@
* (e.g. Launcher activity). To run this test: `atest
* FlickerTests:ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker: LegacyFlickerTest) :
+class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker: LegacyFlickerTest) :
BaseTest(flicker) {
private val imeTestApp =
ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
@@ -86,23 +84,28 @@
val layerTrace = flicker.reader.readLayersTrace() ?: error("Unable to read layers trace")
// Find the entries immediately after the IME snapshot has disappeared
- val imeSnapshotRemovedEntries = layerTrace.entries.asSequence()
- .zipWithNext { prev, next ->
- if (ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(prev.visibleLayers) &&
- !ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(next.visibleLayers)) {
- next
- } else {
- null
+ val imeSnapshotRemovedEntries =
+ layerTrace.entries
+ .asSequence()
+ .zipWithNext { prev, next ->
+ if (
+ ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(prev.visibleLayers) &&
+ !ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(next.visibleLayers)
+ ) {
+ next
+ } else {
+ null
+ }
}
- }
- .filterNotNull()
+ .filterNotNull()
// If we find it, make sure the IME is visible and fully animated in.
imeSnapshotRemovedEntries.forEach { entry ->
val entrySubject = LayerTraceEntrySubject(entry)
- val imeLayerSubjects = entrySubject.subjects.filter {
- ComponentNameMatcher.IME.layerMatchesAnyOf(it.layer) && it.isVisible
- }
+ val imeLayerSubjects =
+ entrySubject.subjects.filter {
+ ComponentNameMatcher.IME.layerMatchesAnyOf(it.layer) && it.isVisible
+ }
entrySubject
.check { "InputMethod must exist and be visible" }
@@ -110,10 +113,7 @@
.isEqual(true)
imeLayerSubjects.forEach { imeLayerSubject ->
- imeLayerSubject
- .check { "alpha" }
- .that(imeLayerSubject.layer.color.a)
- .isEqual(1.0f)
+ imeLayerSubject.check { "alpha" }.that(imeLayerSubject.layer.color.a).isEqual(1.0f)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm.kt
deleted file mode 100644
index 6d9ea22..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTestCfArm(flicker: LegacyFlickerTest) :
- ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index ae05e37..05babd67 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.helpers.reopenAppFromOverview
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import com.android.server.wm.flicker.helpers.setRotation
@@ -37,11 +36,10 @@
/**
* Test IME window opening transitions. To run this test: `atest FlickerTests:ReOpenImeWindowTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker: LegacyFlickerTest) :
+class ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker: LegacyFlickerTest) :
BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm.kt
deleted file mode 100644
index 92b3968..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeOnAppStartWhenLaunchingAppFromOverviewTestCfArm(flicker: LegacyFlickerTest) :
- ShowImeOnAppStartWhenLaunchingAppFromOverviewTest(flicker) {
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index c991651..aff8e65 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -39,12 +38,11 @@
* Test IME windows switching with 2-Buttons or gestural navigation. To run this test: `atest
* FlickerTests:SwitchImeWindowsFromGestureNavTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Presubmit
-open class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest(flicker: LegacyFlickerTest) :
+class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest(flicker: LegacyFlickerTest) :
BaseTest(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
private val imeTestApp =
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm.kt
deleted file mode 100644
index 09bfacc..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Presubmit
-open class ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTestCfArm(flicker: LegacyFlickerTest) :
- ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 9763521..4ffdcea 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import com.android.server.wm.flicker.helpers.ImeStateInitializeHelper
@@ -75,11 +74,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeOnAppStartWhenLaunchingAppTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class ShowImeOnAppStartWhenLaunchingAppTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
private val initializeApp = ImeStateInitializeHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
index 7bd5825..918e1ea 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeAppHelper
import org.junit.FixMethodOrder
@@ -33,11 +32,10 @@
import org.junit.runners.Parameterized
/** Test IME window opening transitions. To run this test: `atest FlickerTests:OpenImeWindowTest` */
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeWhenFocusingOnInputFieldTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class ShowImeWhenFocusingOnInputFieldTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTestCfArm.kt
deleted file mode 100644
index f8c8149..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeWhenFocusingOnInputFieldTestCfArm(flicker: LegacyFlickerTest) :
- ShowImeWhenFocusingOnInputFieldTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 0b168ba..6ad235c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -26,7 +26,6 @@
import android.view.WindowInsets.Type.ime
import android.view.WindowInsets.Type.navigationBars
import android.view.WindowInsets.Type.statusBars
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import org.junit.Assert.assertFalse
@@ -41,12 +40,10 @@
* Test IME snapshot mechanism won't apply when transitioning from non-IME focused dialog activity.
* To run this test: `atest FlickerTests:LaunchAppShowImeAndDialogThemeAppTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeWhileDismissingThemedPopupDialogTest(flicker: LegacyFlickerTest) :
- BaseTest(flicker) {
+class ShowImeWhileDismissingThemedPopupDialogTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTestCfArm.kt
deleted file mode 100644
index ad41b81..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTestCfArm.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeWhileDismissingThemedPopupDialogTestCfArm(flicker: LegacyFlickerTest) :
- ShowImeWhileDismissingThemedPopupDialogTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index 7722c93..f1bc125 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.traces.parsers.WindowManagerStateHelper
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
@@ -41,11 +40,10 @@
* Test IME window layer will be associated with the app task when going to the overview screen. To
* run this test: `atest FlickerTests:OpenImeWindowToOverViewTest`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class ShowImeWhileEnteringOverviewTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val imeTestApp =
ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTestCfArm.kt
deleted file mode 100644
index 90fbbf9..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTestCfArm.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.ime
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ShowImeWhileEnteringOverviewTestCfArm(flicker: LegacyFlickerTest) :
- ShowImeWhileEnteringOverviewTest(flicker)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
index 3461907..89ab41e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.traces.parsers.toFlickerComponent
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -53,11 +52,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ActivityTransitionTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class ActivityTransitionTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
deleted file mode 100644
index 6bbf40e..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivityTransitionTestCfArm.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ActivityTransitionTestCfArm(flicker: LegacyFlickerTest) : ActivityTransitionTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index ae1f78a..57eb172 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,12 +50,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIconColdTest(flicker: LegacyFlickerTest) :
- OpenAppFromLauncherTransition(flicker) {
+class OpenAppFromIconColdTest(flicker: LegacyFlickerTest) : OpenAppFromLauncherTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
deleted file mode 100644
index 4fd4a61..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTestCfArm.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import android.platform.test.annotations.FlakyTest
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/** Some assertions will fail because of b/264415996 */
-@FlickerServiceCompatible
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIconColdTestCfArm(flicker: LegacyFlickerTest) : OpenAppFromIconColdTest(flicker) {
- @Test
- @FlakyTest
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index c95c548..f575fcc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -21,7 +21,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import org.junit.FixMethodOrder
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
@@ -34,11 +33,10 @@
*
* Notes: Some default assertions are inherited [OpenAppTransition]
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIntentColdAfterCameraTest(flicker: LegacyFlickerTest) :
+class OpenAppFromIntentColdAfterCameraTest(flicker: LegacyFlickerTest) :
OpenAppFromLauncherTransition(flicker) {
private val cameraApp = CameraAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
deleted file mode 100644
index 117cff2..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTestCfArm.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIntentColdAfterCameraTestCfArm(flicker: LegacyFlickerTest) :
- OpenAppFromIntentColdAfterCameraTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index e39a578..93d0520 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
import org.junit.Test
@@ -53,12 +52,11 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@FlickerServiceCompatible
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIntentColdTest(flicker: LegacyFlickerTest) :
+class OpenAppFromIntentColdTest(flicker: LegacyFlickerTest) :
OpenAppFromLauncherTransition(flicker) {
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
deleted file mode 100644
index 6d0b6f4..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTestCfArm.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import android.platform.test.annotations.FlakyTest
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@FlickerServiceCompatible
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIntentColdTestCfArm(flicker: LegacyFlickerTest) :
- OpenAppFromIntentColdTest(flicker) {
- @FlakyTest(bugId = 273696733)
- @Test
- override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
-
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index d2c3807..0197e66 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
import org.junit.Test
@@ -53,12 +52,11 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@FlickerServiceCompatible
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromIntentWarmTest(flicker: LegacyFlickerTest) :
+class OpenAppFromIntentWarmTest(flicker: LegacyFlickerTest) :
OpenAppFromLauncherTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
deleted file mode 100644
index 3e0958a..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTestCfArm.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@FlickerServiceCompatible
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromIntentWarmTestCfArm(flicker: LegacyFlickerTest) :
- OpenAppFromIntentWarmTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index eec6bfd..f1cd69a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -24,7 +24,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import org.junit.FixMethodOrder
import org.junit.Test
@@ -55,13 +54,11 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@FlickerServiceCompatible
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromOverviewTest(flicker: LegacyFlickerTest) :
- OpenAppFromLauncherTransition(flicker) {
+class OpenAppFromOverviewTest(flicker: LegacyFlickerTest) : OpenAppFromLauncherTransition(flicker) {
/** Defines the transition used to run the test */
override val transition: FlickerBuilder.() -> Unit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTestCfArm.kt
deleted file mode 100644
index ab6a1ea..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTestCfArm.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.launch
-
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/** Some assertions will fail because of b/264415996 */
-@FlickerServiceCompatible
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromOverviewTestCfArm(flicker: LegacyFlickerTest) :
- OpenAppFromOverviewTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OWNERS b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OWNERS
new file mode 100644
index 0000000..68c37bd
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OWNERS
@@ -0,0 +1,2 @@
+# Android > Android OS & Apps > System UI > Internal Only > Notifications
+# https://b.corp.google.com/issues/new?component=181562&template=686802
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index 4e8a697..3f3542d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -59,6 +59,10 @@
get() = {
super.transition(this)
+ transitions {
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+
setup {
device.wakeUpAndGoToHomeScreen()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
index 50dec3b..fbdba7b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
import org.junit.FixMethodOrder
import org.junit.Ignore
@@ -37,7 +36,6 @@
*
* To run this test: `atest FlickerTests:OpenAppFromNotificationCold`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTestCfArm.kt
deleted file mode 100644
index a147171..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTestCfArm.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.notification
-
-import android.platform.test.annotations.Postsubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Postsubmit
-class OpenAppFromNotificationColdTestCfArm(flicker: LegacyFlickerTest) :
- OpenAppFromNotificationColdTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
index 19a070b..a6cf8ee 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
@@ -26,7 +26,6 @@
import android.tools.device.helpers.wakeUpAndGoToHomeScreen
import android.view.WindowInsets
import android.view.WindowManager
-import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.NotificationAppHelper
@@ -49,7 +48,6 @@
*
* To run this test: `atest FlickerTests:OpenAppFromNotificationWarm`
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTestCfArm.kt
deleted file mode 100644
index 98356d7..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTestCfArm.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.notification
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromNotificationWarmTestCfArm(flicker: LegacyFlickerTest) :
- OpenAppFromNotificationWarmTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 7883910..50ff62b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -25,7 +25,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -48,11 +47,10 @@
* Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class QuickSwitchBetweenTwoAppsBackTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt
deleted file mode 100644
index f68cd5c..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTestCfArm.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.quickswitch
-
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class QuickSwitchBetweenTwoAppsBackTestCfArm(flicker: LegacyFlickerTest) :
- QuickSwitchBetweenTwoAppsBackTest(flicker) {
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
- )
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 1c4c7cd..aee9163 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -25,7 +25,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
@@ -49,11 +48,10 @@
* Swipe left from the bottom of the screen to quick switch forward to the second app [testApp2]
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsForwardTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class QuickSwitchBetweenTwoAppsForwardTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp1 = SimpleAppHelper(instrumentation)
private val testApp2 = NonResizeableAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt
deleted file mode 100644
index 3de58ac..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTestCfArm.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.quickswitch
-
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class QuickSwitchBetweenTwoAppsForwardTestCfArm(flicker: LegacyFlickerTest) :
- QuickSwitchBetweenTwoAppsForwardTest(flicker) {
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
- )
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index 6417456..d6a951d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -26,7 +26,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.BaseTest
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import org.junit.FixMethodOrder
@@ -48,11 +47,10 @@
* Swipe right from the bottom of the screen to quick switch back to the app
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchFromLauncherTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
+class QuickSwitchFromLauncherTest(flicker: LegacyFlickerTest) : BaseTest(flicker) {
private val testApp = SimpleAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt
deleted file mode 100644
index 84fc754..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTestCfArm.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.quickswitch
-
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchFromLauncherTestCfArm(flicker: LegacyFlickerTest) :
- QuickSwitchFromLauncherTest(flicker) {
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL),
- // TODO: Test with 90 rotation
- supportedRotations = listOf(Rotation.ROTATION_0)
- )
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 842ece3..1987a68 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -23,7 +23,6 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -81,11 +80,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ChangeAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
+class ChangeAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
override val testApp = SimpleAppHelper(instrumentation)
override val transition: FlickerBuilder.() -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTestCfArm.kt
deleted file mode 100644
index 1ab5c5a..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTestCfArm.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.rotation
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ChangeAppRotationTestCfArm(flicker: LegacyFlickerTest) : ChangeAppRotationTest(flicker) {
- companion object {
- /**
- * Creates the test configurations.
- *
- * See [LegacyFlickerTestFactory.rotationTests] for configuring screen orientation and
- * navigation modes.
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() = LegacyFlickerTestFactory.rotationTests()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index b6ad3cc7..5b127c8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -26,7 +26,6 @@
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import android.view.WindowManager
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
@@ -88,11 +87,10 @@
* apps are running before setup
* ```
*/
-@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SeamlessAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
+class SeamlessAppRotationTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
override val testApp = SeamlessRotationAppHelper(instrumentation)
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTestCfArm.kt
deleted file mode 100644
index 592be05..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTestCfArm.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker.rotation
-
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import com.android.server.wm.flicker.testapp.ActivityOptions
-import org.junit.FixMethodOrder
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/** This test should fail because of b/264518826 */
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SeamlessAppRotationTestCfArm(flicker: LegacyFlickerTest) :
- SeamlessAppRotationTest(flicker) {
- companion object {
- /**
- * Creates the test configurations for seamless rotation based on the default rotation tests
- * from [LegacyFlickerTestFactory.rotationTests], but adding a flag (
- * [ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD]) to indicate if the app should
- * starve the UI thread of not
- */
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.rotationTests().flatMap { sourceCfg ->
- val legacyCfg = sourceCfg as LegacyFlickerTest
- val defaultRun = createConfig(legacyCfg, starveUiThread = false)
- val busyUiRun = createConfig(legacyCfg, starveUiThread = true)
- listOf(defaultRun, busyUiRun)
- }
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/Utils.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/Utils.kt
new file mode 100644
index 0000000..8242e9a
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/Utils.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service
+
+import android.app.Instrumentation
+import android.platform.test.rule.NavigationModeRule
+import android.platform.test.rule.PressHomeRule
+import android.platform.test.rule.UnlockScreenRule
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.apphelpers.MessagingAppHelper
+import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.device.flicker.rules.LaunchAppRule
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.rules.RuleChain
+
+object Utils {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ fun testSetupRule(navigationMode: NavBar, rotation: Rotation): RuleChain {
+ return RuleChain.outerRule(UnlockScreenRule())
+ .around(
+ NavigationModeRule(navigationMode.value, /* changeNavigationModeAfterTest */ false)
+ )
+ .around(
+ LaunchAppRule(MessagingAppHelper(instrumentation), clearCacheAfterParsing = false)
+ )
+ .around(RemoveAllTasksButHomeRule())
+ .around(
+ ChangeDisplayOrientationRule(
+ rotation,
+ resetOrientationAfterTest = false,
+ clearCacheAfterParsing = false
+ )
+ )
+ .around(PressHomeRule())
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
new file mode 100644
index 0000000..030b292
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
@@ -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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppBackButton3ButtonLandscape :
+ CloseAppBackButton(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
new file mode 100644
index 0000000..770da143
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
@@ -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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppBackButton3ButtonPortrait :
+ CloseAppBackButton(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
new file mode 100644
index 0000000..4b2206d7
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
@@ -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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppBackButtonGesturalNavLandscape :
+ CloseAppBackButton(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
new file mode 100644
index 0000000..54b471e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
@@ -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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppBackButtonGesturalNavPortrait :
+ CloseAppBackButton(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppBackButtonTest() = super.closeAppBackButtonTest()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
new file mode 100644
index 0000000..47c2529
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppHomeButton3ButtonLandscape : CloseAppHomeButton(Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppHomeButton() = super.closeAppHomeButton()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
new file mode 100644
index 0000000..b18148f
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppHomeButton3ButtonPortrait : CloseAppHomeButton(Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppHomeButton() = super.closeAppHomeButton()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
new file mode 100644
index 0000000..8543015
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppSwipeToHomeGesturalNavLandscape : CloseAppSwipeToHome(Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppSwipeToHome() = super.closeAppSwipeToHome()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
new file mode 100644
index 0000000..f88963b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.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.server.wm.flicker.service.close.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class CloseAppSwipeToHomeGesturalNavPortrait : CloseAppSwipeToHome(Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_CLOSE_TO_HOME"])
+ @Test
+ override fun closeAppSwipeToHome() = super.closeAppSwipeToHome()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
new file mode 100644
index 0000000..2aaacde
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.close.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class CloseAppBackButton(
+ val gestureMode: NavBar = NavBar.MODE_GESTURAL,
+ val rotation: Rotation = Rotation.ROTATION_0
+) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(gestureMode, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setExpectedRotation(rotation.value)
+ testApp.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun closeAppBackButtonTest() {
+ tapl.pressBack()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
new file mode 100644
index 0000000..08683a3
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.close.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class CloseAppHomeButton(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_3BUTTON, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setExpectedRotation(rotation.value)
+ testApp.launchViaIntent(wmHelper)
+ tapl.setExpectedRotationCheckEnabled(false)
+ }
+
+ @Test
+ open fun closeAppHomeButton() {
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
new file mode 100644
index 0000000..360e114
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.close.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class CloseAppSwipeToHome(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setExpectedRotation(rotation.value)
+ testApp.launchViaIntent(wmHelper)
+ tapl.setExpectedRotationCheckEnabled(false)
+ }
+
+ @Test
+ open fun closeAppSwipeToHome() {
+ tapl.goHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
new file mode 100644
index 0000000..bb18770
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationCold3ButtonNavLandscape :
+ OpenAppFromLockscreenNotificationCold(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationCold() =
+ super.openAppFromLockscreenNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
new file mode 100644
index 0000000..1c3cc21
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationCold3ButtonNavPortrait :
+ OpenAppFromLockscreenNotificationCold(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationCold() =
+ super.openAppFromLockscreenNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
new file mode 100644
index 0000000..46d36db
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationColdGesturalNavLandscape :
+ OpenAppFromLockscreenNotificationCold(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationCold() =
+ super.openAppFromLockscreenNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
new file mode 100644
index 0000000..f6a668fe
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationColdGesturalNavPortrait :
+ OpenAppFromLockscreenNotificationCold(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationCold() =
+ super.openAppFromLockscreenNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
new file mode 100644
index 0000000..93200ba
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape :
+ OpenAppFromLockscreenNotificationWarm(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWarm() =
+ super.openAppFromLockscreenNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
new file mode 100644
index 0000000..f5d41d2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait :
+ OpenAppFromLockscreenNotificationWarm(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWarm() =
+ super.openAppFromLockscreenNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
new file mode 100644
index 0000000..28f322b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWarmGesturalNavLandscape :
+ OpenAppFromLockscreenNotificationWarm(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWarm() =
+ super.openAppFromLockscreenNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
new file mode 100644
index 0000000..beb3fae
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWarmGesturalNavPortrait :
+ OpenAppFromLockscreenNotificationWarm(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWarm() =
+ super.openAppFromLockscreenNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
new file mode 100644
index 0000000..b34da72
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape :
+ OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWithOverlayApp() =
+ super.openAppFromLockscreenNotificationWithOverlayApp()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
new file mode 100644
index 0000000..b163897
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait :
+ OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWithOverlayApp() =
+ super.openAppFromLockscreenNotificationWithOverlayApp()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
new file mode 100644
index 0000000..19b533e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape :
+ OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWithOverlayApp() =
+ super.openAppFromLockscreenNotificationWithOverlayApp()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
new file mode 100644
index 0000000..c9ed4f4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait :
+ OpenAppFromLockscreenNotificationWithOverlayApp(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromLockscreenNotificationWithOverlayApp() =
+ super.openAppFromLockscreenNotificationWithOverlayApp()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
new file mode 100644
index 0000000..866190f
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationCold3ButtonNavLandscape :
+ OpenAppFromNotificationCold(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationCold() = super.openAppFromNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
new file mode 100644
index 0000000..a8d6283
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationCold3ButtonNavPortrait :
+ OpenAppFromNotificationCold(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationCold() = super.openAppFromNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
new file mode 100644
index 0000000..ef84c3f
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationColdGesturalNavLandscape :
+ OpenAppFromNotificationCold(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationCold() = super.openAppFromNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
new file mode 100644
index 0000000..5bb6b37
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationColdGesturalNavPortrait :
+ OpenAppFromNotificationCold(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationCold() = super.openAppFromNotificationCold()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
new file mode 100644
index 0000000..39f25e9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationWarm3ButtonNavLandscape :
+ OpenAppFromNotificationWarm(NavBar.MODE_3BUTTON, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationWarm() = super.openAppFromNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
new file mode 100644
index 0000000..28816bc
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationWarm3ButtonNavPortrait :
+ OpenAppFromNotificationWarm(NavBar.MODE_3BUTTON, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationWarm() = super.openAppFromNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
new file mode 100644
index 0000000..94ffe4e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationWarmGesturalNavLandscape :
+ OpenAppFromNotificationWarm(NavBar.MODE_GESTURAL, Rotation.ROTATION_90) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationWarm() = super.openAppFromNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
new file mode 100644
index 0000000..e5f5ec4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
@@ -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.server.wm.flicker.service.notification.flicker
+
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class OpenAppFromNotificationWarmGesturalNavPortrait :
+ OpenAppFromNotificationWarm(NavBar.MODE_GESTURAL, Rotation.ROTATION_0) {
+ @ExpectedScenarios(["APP_LAUNCH_FROM_NOTIFICATION"])
+ @Test
+ override fun openAppFromNotificationWarm() = super.openAppFromNotificationWarm()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
new file mode 100644
index 0000000..ac4e169
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.scenarios
+
+import android.app.Instrumentation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.view.WindowInsets
+import android.view.WindowManager
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.launcher3.tapl.LauncherInstrumentation
+
+object NotificationUtils {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+
+ fun openNotification(openingNotificationsFromLockScreen: Boolean) {
+ var startY = 10
+ var endY = 3 * device.displayHeight / 4
+ var steps = 25
+ if (openingNotificationsFromLockScreen) {
+ val wm: WindowManager =
+ instrumentation.context.getSystemService(WindowManager::class.java)
+ ?: error("Unable to connect to WindowManager service")
+ val metricInsets = wm.currentWindowMetrics.windowInsets
+ val insets =
+ metricInsets.getInsetsIgnoringVisibility(
+ WindowInsets.Type.statusBars() or WindowInsets.Type.displayCutout()
+ )
+
+ startY = insets.top + 100
+ endY = device.displayHeight / 2
+ steps = 4
+ }
+
+ // Swipe down to show the notification shade
+ val x = device.displayWidth / 2
+ device.swipe(x, startY, x, endY, steps)
+ device.waitForIdle(2000)
+ instrumentation.uiAutomation.syncInputTransactions()
+
+ // Launch the activity by clicking the notification
+ val notification =
+ device.wait(Until.findObject(By.text("Flicker Test Notification")), 2000L)
+ notification?.click() ?: error("Notification not found")
+ instrumentation.uiAutomation.syncInputTransactions()
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
new file mode 100644
index 0000000..9c53ab3
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.NotificationAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+abstract class OpenAppFromLockscreenNotificationCold(
+ val gestureMode: NavBar = NavBar.MODE_GESTURAL,
+ val rotation: Rotation = Rotation.ROTATION_0
+) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
+
+ val openingNotificationsFromLockScreen = true
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(gestureMode, rotation)
+
+ @Before
+ fun setup() {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ testApp.postNotification(wmHelper)
+ device.pressHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+
+ // Close the app that posted the notification to trigger a cold start next time
+ // it is open - can't just kill it because that would remove the notification.
+ tapl.setExpectedRotationCheckEnabled(false)
+ tapl.goHome()
+ tapl.workspace.switchToOverview()
+ tapl.overview.dismissAllTasks()
+
+ device.sleep()
+ wmHelper.StateSyncBuilder().withoutTopVisibleAppWindows().waitForAndVerify()
+ }
+
+ @Test
+ open fun openAppFromLockscreenNotificationCold() {
+ device.wakeUp()
+
+ NotificationUtils.openNotification(openingNotificationsFromLockScreen)
+ // Wait for the app to launch
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
new file mode 100644
index 0000000..31f55d9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.notification.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.NotificationAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+abstract class OpenAppFromLockscreenNotificationWarm(
+ val gestureMode: NavBar = NavBar.MODE_GESTURAL,
+ val rotation: Rotation = Rotation.ROTATION_0
+) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
+
+ private val openingNotificationsFromLockScreen = true
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(gestureMode, rotation)
+
+ @Before
+ fun setup() {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ testApp.postNotification(wmHelper)
+ device.pressHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+
+ device.sleep()
+ wmHelper.StateSyncBuilder().withoutTopVisibleAppWindows().waitForAndVerify()
+ }
+
+ @Test
+ open fun openAppFromLockscreenNotificationWarm() {
+ device.wakeUp()
+
+ NotificationUtils.openNotification(openingNotificationsFromLockScreen)
+ // Wait for the app to launch
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
new file mode 100644
index 0000000..b971555
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
@@ -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.server.wm.flicker.service.notification.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.NotificationAppHelper
+import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+abstract class OpenAppFromLockscreenNotificationWithOverlayApp(
+ val gestureMode: NavBar = NavBar.MODE_GESTURAL,
+ val rotation: Rotation = Rotation.ROTATION_0
+) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val showWhenLockedApp = ShowWhenLockedAppHelper(instrumentation)
+ private val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
+
+ // Although we are technically still locked here, the overlay app means we should open the
+ // notification shade as if we were unlocked.
+ private val openingNotificationsFromLockScreen = false
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(gestureMode, rotation)
+
+ @Before
+ fun setup() {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ testApp.postNotification(wmHelper)
+ device.pressHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+
+ // Close the app that posted the notification to trigger a cold start next time
+ // it is open - can't just kill it because that would remove the notification.
+ tapl.setExpectedRotationCheckEnabled(false)
+ tapl.goHome()
+ tapl.workspace.switchToOverview()
+ tapl.overview.dismissAllTasks()
+
+ device.sleep()
+ wmHelper.StateSyncBuilder().withoutTopVisibleAppWindows().waitForAndVerify()
+
+ device.wakeUpAndGoToHomeScreen()
+
+ // Launch an activity that is shown when the device is locked
+ showWhenLockedApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withFullScreenApp(showWhenLockedApp).waitForAndVerify()
+
+ device.sleep()
+ wmHelper.StateSyncBuilder().withoutTopVisibleAppWindows().waitForAndVerify()
+ }
+
+ @Test
+ open fun openAppFromLockscreenNotificationWithOverlayApp() {
+ device.wakeUp()
+ NotificationUtils.openNotification(openingNotificationsFromLockScreen)
+ // Wait for the app to launch
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ showWhenLockedApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
new file mode 100644
index 0000000..fed077e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.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.server.wm.flicker.service.notification.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.NotificationAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+abstract class OpenAppFromNotificationCold(
+ val gestureMode: NavBar = NavBar.MODE_GESTURAL,
+ val rotation: Rotation = Rotation.ROTATION_0
+) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val device = UiDevice.getInstance(instrumentation)
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(gestureMode, rotation)
+
+ private val openingNotificationsFromLockScreen = false
+
+ @Before
+ fun setup() {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ testApp.postNotification(wmHelper)
+ device.pressHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+
+ // Close the app that posted the notification to trigger a cold start next time
+ // it is open - can't just kill it because that would remove the notification.
+ tapl.setExpectedRotationCheckEnabled(false)
+ tapl.goHome()
+ tapl.workspace.switchToOverview()
+ tapl.overview.dismissAllTasks()
+ }
+
+ @Test
+ open fun openAppFromNotificationCold() {
+ NotificationUtils.openNotification(openingNotificationsFromLockScreen)
+ // Wait for the app to launch
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
new file mode 100644
index 0000000..403790e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.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.server.wm.flicker.service.notification.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.NotificationAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+abstract class OpenAppFromNotificationWarm(
+ val gestureMode: NavBar = NavBar.MODE_GESTURAL,
+ val rotation: Rotation = Rotation.ROTATION_0
+) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val device = UiDevice.getInstance(instrumentation)
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
+
+ private val openingNotificationsFromLockScreen = false
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(gestureMode, rotation)
+
+ @Before
+ fun setup() {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ testApp.postNotification(wmHelper)
+ device.pressHome()
+ wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
+ }
+
+ @Test
+ open fun openAppFromNotificationWarm() {
+ NotificationUtils.openNotification(openingNotificationsFromLockScreen)
+ // Wait for the app to launch
+ wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
new file mode 100644
index 0000000..d611a42
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.quickswitch.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class QuickSwitchBetweenTwoAppsBackGesturalNavLandscape :
+ QuickSwitchBetweenTwoAppsBack(Rotation.ROTATION_90) {
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun quickSwitchBetweenTwoAppsBack() = super.quickSwitchBetweenTwoAppsBack()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
new file mode 100644
index 0000000..e6bcbba
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.quickswitch.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class QuickSwitchBetweenTwoAppsBackGesturalNavPortrait :
+ QuickSwitchBetweenTwoAppsBack(Rotation.ROTATION_0) {
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun quickSwitchBetweenTwoAppsBack() = super.quickSwitchBetweenTwoAppsBack()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
new file mode 100644
index 0000000..2a26d63
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.quickswitch.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape :
+ QuickSwitchBetweenTwoAppsForward(Rotation.ROTATION_90) {
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun quickSwitchBetweenTwoAppsForward() = super.quickSwitchBetweenTwoAppsForward()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
new file mode 100644
index 0000000..5ce7143
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.service.quickswitch.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait :
+ QuickSwitchBetweenTwoAppsForward(Rotation.ROTATION_0) {
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun quickSwitchBetweenTwoAppsForward() = super.quickSwitchBetweenTwoAppsForward()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
new file mode 100644
index 0000000..cff47bb
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.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.server.wm.flicker.service.quickswitch.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class QuickSwitchFromLauncherGesturalNavLandscape : QuickSwitchFromLauncher(Rotation.ROTATION_90) {
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun quickSwitchFromLauncher() = super.quickSwitchFromLauncher()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
new file mode 100644
index 0000000..33095a6
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.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.server.wm.flicker.service.quickswitch.flicker
+
+import android.tools.common.Rotation
+import android.tools.common.flicker.FlickerConfig
+import android.tools.common.flicker.annotation.ExpectedScenarios
+import android.tools.common.flicker.annotation.FlickerConfigProvider
+import android.tools.common.flicker.config.FlickerConfig
+import android.tools.common.flicker.config.FlickerServiceConfig
+import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class QuickSwitchFromLauncherGesturalNavPortrait : QuickSwitchFromLauncher(Rotation.ROTATION_0) {
+ @ExpectedScenarios(["QUICKSWITCH"])
+ @Test
+ override fun quickSwitchFromLauncher() = super.quickSwitchFromLauncher()
+
+ companion object {
+ @JvmStatic
+ @FlickerConfigProvider
+ fun flickerConfigProvider(): FlickerConfig =
+ FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
new file mode 100644
index 0000000..93130c4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.server.wm.flicker.service.quickswitch.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class QuickSwitchBetweenTwoAppsBack(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp1 = SimpleAppHelper(instrumentation)
+ private val testApp2 = NonResizeableAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setExpectedRotation(rotation.value)
+ tapl.setIgnoreTaskbarVisibility(true)
+ testApp1.launchViaIntent(wmHelper)
+ testApp2.launchViaIntent(wmHelper)
+ }
+
+ @Test
+ open fun quickSwitchBetweenTwoAppsBack() {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ wmHelper
+ .StateSyncBuilder()
+ .withFullScreenApp(testApp1)
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp1.exit(wmHelper)
+ testApp2.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
new file mode 100644
index 0000000..4941eea
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
@@ -0,0 +1,75 @@
+/*
+ * 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.server.wm.flicker.service.quickswitch.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class QuickSwitchBetweenTwoAppsForward(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp1 = SimpleAppHelper(instrumentation)
+ private val testApp2 = NonResizeableAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setExpectedRotation(rotation.value)
+
+ testApp1.launchViaIntent(wmHelper)
+ testApp2.launchViaIntent(wmHelper)
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ wmHelper
+ .StateSyncBuilder()
+ .withFullScreenApp(testApp1)
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
+ }
+
+ @Test
+ open fun quickSwitchBetweenTwoAppsForward() {
+ tapl.launchedAppState.quickSwitchToPreviousAppSwipeLeft()
+ wmHelper
+ .StateSyncBuilder()
+ .withFullScreenApp(testApp2)
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp1.exit(wmHelper)
+ testApp2.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
new file mode 100644
index 0000000..7afe526
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.server.wm.flicker.service.quickswitch.scenarios
+
+import android.app.Instrumentation
+import android.tools.common.NavBar
+import android.tools.common.Rotation
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.service.Utils
+import org.junit.After
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class QuickSwitchFromLauncher(val rotation: Rotation = Rotation.ROTATION_0) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val testApp = SimpleAppHelper(instrumentation)
+
+ @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation)
+
+ @Before
+ fun setup() {
+ tapl.setExpectedRotationCheckEnabled(false)
+
+ tapl.setExpectedRotation(rotation.value)
+
+ testApp.launchViaIntent(wmHelper)
+ tapl.goHome()
+ wmHelper
+ .StateSyncBuilder()
+ .withHomeActivityVisible()
+ .withWindowSurfaceDisappeared(testApp)
+ .waitForAndVerify()
+ }
+
+ @Test
+ open fun quickSwitchFromLauncher() {
+ tapl.workspace.quickSwitchToPreviousApp()
+ wmHelper
+ .StateSyncBuilder()
+ .withFullScreenApp(testApp)
+ .withNavOrTaskBarVisible()
+ .withStatusBarVisible()
+ .waitForAndVerify()
+ }
+
+ @After
+ fun teardown() {
+ testApp.exit(wmHelper)
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 7a2e74b..68ae806 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -193,6 +193,14 @@
</intent-filter>
</activity>
<activity
+ android:name=".ActivityEmbeddingTrampolineActivity"
+ android:label="ActivityEmbedding Trampoline"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
+ android:theme="@style/CutoutShortEdges"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+ android:exported="false">
+ </activity>
+ <activity
android:name=".ActivityEmbeddingSecondaryActivity"
android:label="ActivityEmbedding Secondary"
android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
index b9d789b..e32a709 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -60,4 +60,12 @@
android:tag="RIGHT_TO_LEFT"
android:text="Launch Placeholder Split in RTL" />
+ <Button
+ android:id="@+id/launch_trampoline_button"
+ android:layout_width="wrap_content"
+ android:layout_height="48dp"
+ android:onClick="launchTrampolineActivity"
+ android:tag="LEFT_TO_RIGHT"
+ android:text="Launch Trampoline Activity" />
+
</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
index 817c79c..3b1a859 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingMainActivity.java
@@ -16,14 +16,12 @@
package com.android.server.wm.flicker.testapp;
-
+import androidx.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
-import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper;
-import androidx.annotation.NonNull;
import androidx.window.embedding.ActivityFilter;
import androidx.window.embedding.ActivityRule;
import androidx.window.embedding.EmbeddingAspectRatio;
@@ -59,6 +57,15 @@
mRuleController = RuleController.getInstance(this);
}
+ /** R.id.launch_trampoline_button onClick */
+ public void launchTrampolineActivity(View view) {
+ final String layoutDirection = view.getTag().toString();
+ mRuleController.clearRules();
+ mRuleController.addRule(createSplitPairRules(layoutDirection));
+ startActivity(new Intent().setComponent(
+ ActivityOptions.ActivityEmbedding.TrampolineActivity.COMPONENT));
+ }
+
/** R.id.launch_secondary_activity_button onClick */
public void launchSecondaryActivity(View view) {
final String layoutDirection = view.getTag().toString();
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingTrampolineActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingTrampolineActivity.java
new file mode 100644
index 0000000..67eac2e
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingTrampolineActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * A Trampoline Activity that launches {@link ActivityEmbeddingSecondaryActivity} and then
+ * finishes itself.
+ */
+public class ActivityEmbeddingTrampolineActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Trampoline activity doesn't have a view.
+ startActivity(new Intent().setComponent(
+ ActivityOptions.ActivityEmbedding.SecondaryActivity.COMPONENT));
+ finish();
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index d84ac42..95c86ac 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -122,6 +122,12 @@
public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
}
+
+ public static class TrampolineActivity {
+ public static final String LABEL = "ActivityEmbeddingTrampolineActivity";
+ public static final ComponentName COMPONENT = new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ActivityEmbeddingTrampolineActivity");
+ }
}
public static class Notification {
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 4fa6fbe..96b685d 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -19,13 +19,26 @@
platform_apis: true,
certificate: "platform",
static_libs: [
+ "androidx.test.core",
"androidx.test.ext.junit",
+ "androidx.test.ext.truth",
"androidx.test.rules",
+ "androidx.test.runner",
+ "androidx.test.uiautomator_uiautomator",
+ "servicestests-utils",
+ "frameworks-base-testutils",
+ "hamcrest-library",
+ "kotlin-test",
"mockito-target-minus-junit4",
+ "platform-test-annotations",
"services.core.unboosted",
"testables",
+ "testng",
"truth-prebuilt",
- "androidx.test.uiautomator_uiautomator",
+ ],
+ libs: [
+ "android.test.mock",
+ "android.test.base",
],
test_suites: ["device-tests"],
}
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
index 20f564e..3b723dd 100644
--- a/tests/Input/AndroidManifest.xml
+++ b/tests/Input/AndroidManifest.xml
@@ -16,11 +16,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.test.input">
- <uses-permission android:name="android.permission.MONITOR_INPUT"/>
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
- <uses-permission android:name="android.permission.INJECT_EVENTS"/>
- <application android:label="InputTest">
+ <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+ <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+
+ <application android:label="InputTest" android:debuggable="true">
<activity android:name=".UnresponsiveGestureMonitorActivity"
android:label="Unresponsive gesture monitor"
diff --git a/tests/Input/OWNERS b/tests/Input/OWNERS
index d701f23..3cffce9 100644
--- a/tests/Input/OWNERS
+++ b/tests/Input/OWNERS
@@ -1 +1,2 @@
+# Bug component: 136048
include /core/java/android/hardware/input/OWNERS
diff --git a/services/tests/servicestests/res/raw/dummy_keyboard_layout.kcm b/tests/Input/res/raw/dummy_keyboard_layout.kcm
similarity index 100%
rename from services/tests/servicestests/res/raw/dummy_keyboard_layout.kcm
rename to tests/Input/res/raw/dummy_keyboard_layout.kcm
diff --git a/services/tests/servicestests/res/raw/input_port_associations.xml b/tests/Input/res/raw/input_port_associations.xml
similarity index 100%
rename from services/tests/servicestests/res/raw/input_port_associations.xml
rename to tests/Input/res/raw/input_port_associations.xml
diff --git a/services/tests/servicestests/res/raw/input_port_associations_bad_displayport.xml b/tests/Input/res/raw/input_port_associations_bad_displayport.xml
similarity index 100%
rename from services/tests/servicestests/res/raw/input_port_associations_bad_displayport.xml
rename to tests/Input/res/raw/input_port_associations_bad_displayport.xml
diff --git a/services/tests/servicestests/res/raw/input_port_associations_bad_xml.xml b/tests/Input/res/raw/input_port_associations_bad_xml.xml
similarity index 100%
rename from services/tests/servicestests/res/raw/input_port_associations_bad_xml.xml
rename to tests/Input/res/raw/input_port_associations_bad_xml.xml
diff --git a/services/tests/servicestests/res/xml/keyboard_layouts.xml b/tests/Input/res/xml/keyboard_layouts.xml
similarity index 100%
rename from services/tests/servicestests/res/xml/keyboard_layouts.xml
rename to tests/Input/res/xml/keyboard_layouts.xml
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt b/tests/Input/src/android/hardware/input/InputDeviceBatteryListenerTest.kt
similarity index 96%
rename from core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt
rename to tests/Input/src/android/hardware/input/InputDeviceBatteryListenerTest.kt
index fdcc7c9..90dff47 100644
--- a/core/tests/coretests/src/android/hardware/input/InputDeviceBatteryListenerTest.kt
+++ b/tests/Input/src/android/hardware/input/InputDeviceBatteryListenerTest.kt
@@ -46,7 +46,7 @@
* Tests for [InputManager.InputDeviceBatteryListener].
*
* Build/Install/Run:
- * atest FrameworksCoreTests:InputDeviceBatteryListenerTest
+ * atest InputTests:InputDeviceBatteryListenerTest
*/
@Presubmit
@RunWith(MockitoJUnitRunner::class)
@@ -63,6 +63,7 @@
@Mock
private lateinit var iInputManagerMock: IInputManager
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
@Before
fun setUp() {
@@ -71,7 +72,7 @@
executor = HandlerExecutor(Handler(testLooper.looper))
registeredListener = null
monitoredDevices.clear()
- InputManagerGlobal.resetInstance(iInputManagerMock)
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock)
inputManager = InputManager(context)
`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
.thenReturn(inputManager)
@@ -112,7 +113,9 @@
@After
fun tearDown() {
- InputManagerGlobal.clearInstance()
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
}
private fun notifyBatteryStateChanged(
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/tests/Input/src/android/hardware/input/InputDeviceLightsManagerTest.java
similarity index 95%
rename from core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
rename to tests/Input/src/android/hardware/input/InputDeviceLightsManagerTest.java
index 1e505ab..080186e 100644
--- a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
+++ b/tests/Input/src/android/hardware/input/InputDeviceLightsManagerTest.java
@@ -43,7 +43,7 @@
import android.util.ArrayMap;
import android.view.InputDevice;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
import org.junit.Before;
@@ -63,7 +63,7 @@
* Tests for {@link InputDeviceLightsManager}.
*
* Build/Install/Run:
- * atest FrameworksCoreTests:InputDeviceLightsManagerTest
+ * atest InputTests:InputDeviceLightsManagerTest
*/
@Presubmit
@RunWith(MockitoJUnitRunner.class)
@@ -78,16 +78,18 @@
private InputManager mInputManager;
@Mock private IInputManager mIInputManagerMock;
+ private InputManagerGlobal.TestSession mInputManagerGlobalSession;
@Before
public void setUp() throws Exception {
- final Context context = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+ final Context context = spy(
+ new ContextWrapper(InstrumentationRegistry.getInstrumentation().getContext()));
when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID});
when(mIInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn(
createInputDevice(DEVICE_ID));
- InputManagerGlobal.resetInstance(mIInputManagerMock);
+ mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock);
mInputManager = new InputManager(context);
when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(mInputManager);
@@ -114,7 +116,9 @@
@After
public void tearDown() {
- InputManagerGlobal.clearInstance();
+ if (mInputManagerGlobalSession != null) {
+ mInputManagerGlobalSession.close();
+ }
}
private InputDevice createInputDevice(int id) {
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/tests/Input/src/android/hardware/input/InputDeviceSensorManagerTest.java
similarity index 94%
rename from core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
rename to tests/Input/src/android/hardware/input/InputDeviceSensorManagerTest.java
index b33cfdd..0e3c200 100644
--- a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
+++ b/tests/Input/src/android/hardware/input/InputDeviceSensorManagerTest.java
@@ -38,7 +38,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.InputDevice;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.internal.annotations.GuardedBy;
@@ -61,7 +61,7 @@
* Tests for {@link InputDeviceSensorManager}.
*
* Build/Install/Run:
- * atest FrameworksCoreTests:InputDeviceSensorManagerTest
+ * atest InputTests:InputDeviceSensorManagerTest
*/
@Presubmit
@RunWith(MockitoJUnitRunner.class)
@@ -77,11 +77,13 @@
private final Object mLock = new Object();
@Mock private IInputManager mIInputManagerMock;
+ private InputManagerGlobal.TestSession mInputManagerGlobalSession;
@Before
public void setUp() throws Exception {
- final Context context = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
- InputManagerGlobal.resetInstance(mIInputManagerMock);
+ final Context context = spy(
+ new ContextWrapper(InstrumentationRegistry.getInstrumentation().getContext()));
+ mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock);
mInputManager = new InputManager(context);
when(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(mInputManager);
@@ -102,7 +104,9 @@
@After
public void tearDown() {
- InputManagerGlobal.clearInstance();
+ if (mInputManagerGlobalSession != null) {
+ mInputManagerGlobalSession.close();
+ }
}
private class InputTestSensorEventListener implements SensorEventListener {
diff --git a/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt b/tests/Input/src/android/hardware/input/InputManagerTest.kt
similarity index 93%
rename from core/tests/coretests/src/android/hardware/input/InputManagerTest.kt
rename to tests/Input/src/android/hardware/input/InputManagerTest.kt
index 2ebe362..152dde9 100644
--- a/core/tests/coretests/src/android/hardware/input/InputManagerTest.kt
+++ b/tests/Input/src/android/hardware/input/InputManagerTest.kt
@@ -41,7 +41,7 @@
* Tests for [InputManager].
*
* Build/Install/Run:
- * atest FrameworksCoreTests:InputManagerTest
+ * atest InputTests:InputManagerTest
*/
@Presubmit
@RunWith(MockitoJUnitRunner::class)
@@ -63,11 +63,12 @@
@Mock
private lateinit var iInputManager: IInputManager
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
@Before
fun setUp() {
context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
- InputManagerGlobal.resetInstance(iInputManager)
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
inputManager = InputManager(context)
`when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager)
`when`(iInputManager.inputDeviceIds).then {
@@ -77,7 +78,9 @@
@After
fun tearDown() {
- InputManagerGlobal.clearInstance()
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
}
private fun notifyDeviceChanged(
diff --git a/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt b/tests/Input/src/android/hardware/input/KeyboardBacklightListenerTest.kt
similarity index 94%
rename from core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt
rename to tests/Input/src/android/hardware/input/KeyboardBacklightListenerTest.kt
index ce816ab..23135b2 100644
--- a/core/tests/coretests/src/android/hardware/input/KeyboardBacklightListenerTest.kt
+++ b/tests/Input/src/android/hardware/input/KeyboardBacklightListenerTest.kt
@@ -45,7 +45,7 @@
* Tests for [InputManager.KeyboardBacklightListener].
*
* Build/Install/Run:
- * atest FrameworksCoreTests:KeyboardBacklightListenerTest
+ * atest InputTests:KeyboardBacklightListenerTest
*/
@Presubmit
@RunWith(MockitoJUnitRunner::class)
@@ -58,6 +58,7 @@
private lateinit var executor: Executor
private lateinit var context: Context
private lateinit var inputManager: InputManager
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
@Mock
private lateinit var iInputManagerMock: IInputManager
@@ -65,7 +66,7 @@
@Before
fun setUp() {
context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
- InputManagerGlobal.resetInstance(iInputManagerMock)
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManagerMock)
testLooper = TestLooper()
executor = HandlerExecutor(Handler(testLooper.looper))
registeredListener = null
@@ -99,7 +100,9 @@
@After
fun tearDown() {
- InputManagerGlobal.clearInstance()
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
}
private fun notifyKeyboardBacklightChanged(
diff --git a/core/tests/coretests/src/android/hardware/input/VirtualKeyEventTest.java b/tests/Input/src/android/hardware/input/VirtualKeyEventTest.java
similarity index 100%
rename from core/tests/coretests/src/android/hardware/input/VirtualKeyEventTest.java
rename to tests/Input/src/android/hardware/input/VirtualKeyEventTest.java
diff --git a/core/tests/coretests/src/android/hardware/input/VirtualMouseButtonEventTest.java b/tests/Input/src/android/hardware/input/VirtualMouseButtonEventTest.java
similarity index 100%
rename from core/tests/coretests/src/android/hardware/input/VirtualMouseButtonEventTest.java
rename to tests/Input/src/android/hardware/input/VirtualMouseButtonEventTest.java
diff --git a/core/tests/coretests/src/android/hardware/input/VirtualMouseRelativeEventTest.java b/tests/Input/src/android/hardware/input/VirtualMouseRelativeEventTest.java
similarity index 100%
rename from core/tests/coretests/src/android/hardware/input/VirtualMouseRelativeEventTest.java
rename to tests/Input/src/android/hardware/input/VirtualMouseRelativeEventTest.java
diff --git a/core/tests/coretests/src/android/hardware/input/VirtualMouseScrollEventTest.java b/tests/Input/src/android/hardware/input/VirtualMouseScrollEventTest.java
similarity index 100%
rename from core/tests/coretests/src/android/hardware/input/VirtualMouseScrollEventTest.java
rename to tests/Input/src/android/hardware/input/VirtualMouseScrollEventTest.java
diff --git a/core/tests/coretests/src/android/hardware/input/VirtualTouchEventTest.java b/tests/Input/src/android/hardware/input/VirtualTouchEventTest.java
similarity index 100%
rename from core/tests/coretests/src/android/hardware/input/VirtualTouchEventTest.java
rename to tests/Input/src/android/hardware/input/VirtualTouchEventTest.java
diff --git a/services/tests/servicestests/src/com/android/server/input/AmbientKeyboardBacklightControllerTests.kt b/tests/Input/src/com/android/server/input/AmbientKeyboardBacklightControllerTests.kt
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/input/AmbientKeyboardBacklightControllerTests.kt
rename to tests/Input/src/com/android/server/input/AmbientKeyboardBacklightControllerTests.kt
index 98b4628..ad481df 100644
--- a/services/tests/servicestests/src/com/android/server/input/AmbientKeyboardBacklightControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/AmbientKeyboardBacklightControllerTests.kt
@@ -55,7 +55,7 @@
* Tests for {@link AmbientKeyboardBacklightController}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:AmbientKeyboardBacklightControllerTests
+ * atest InputTests:AmbientKeyboardBacklightControllerTests
*/
@Presubmit
class AmbientKeyboardBacklightControllerTests {
diff --git a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt b/tests/Input/src/com/android/server/input/BatteryControllerTests.kt
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
rename to tests/Input/src/com/android/server/input/BatteryControllerTests.kt
index c36122b..f2724e6 100644
--- a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/BatteryControllerTests.kt
@@ -167,7 +167,7 @@
* Tests for {@link InputDeviceBatteryController}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:InputDeviceBatteryControllerTests
+ * atest InputTests:InputDeviceBatteryControllerTests
*/
@Presubmit
class BatteryControllerTests {
@@ -198,13 +198,14 @@
private lateinit var context: TestableContext
private lateinit var testLooper: TestLooper
private lateinit var devicesChangedListener: IInputDevicesChangedListener
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
private val deviceGenerationMap = mutableMapOf<Int /*deviceId*/, Int /*generation*/>()
@Before
fun setup() {
context = TestableContext(ApplicationProvider.getApplicationContext())
testLooper = TestLooper()
- InputManagerGlobal.resetInstance(iInputManager)
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
val inputManager = InputManager(context)
context.addMockSystemService(InputManager::class.java, inputManager)
`when`(iInputManager.inputDeviceIds).then {
@@ -222,6 +223,13 @@
testLooper.dispatchAll()
}
+ @After
+ fun tearDown() {
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
+ }
+
private fun notifyDeviceChanged(
deviceId: Int,
hasBattery: Boolean = true,
@@ -253,11 +261,6 @@
.adapter.getRemoteDevice(address)
}
- @After
- fun tearDown() {
- InputManagerGlobal.clearInstance()
- }
-
@Test
fun testRegisterAndUnregisterBinderLifecycle() {
val listener = createMockListener()
diff --git a/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java b/tests/Input/src/com/android/server/input/ConfigurationProcessorTest.java
similarity index 87%
rename from services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java
rename to tests/Input/src/com/android/server/input/ConfigurationProcessorTest.java
index 2bd4a3a..9a49d91 100644
--- a/services/tests/servicestests/src/com/android/server/input/ConfigurationProcessorTest.java
+++ b/tests/Input/src/com/android/server/input/ConfigurationProcessorTest.java
@@ -22,7 +22,7 @@
import android.content.Context;
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
@@ -43,12 +43,12 @@
@Before
public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getContext();
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
}
@Test
public void testGetInputPortAssociations() {
- final int res = com.android.frameworks.servicestests.R.raw.input_port_associations;
+ final int res = com.android.test.input.R.raw.input_port_associations;
InputStream xml = mContext.getResources().openRawResource(res);
Map<String, Integer> associations = null;
try {
@@ -65,7 +65,7 @@
@Test
public void testGetInputPortAssociationsBadDisplayport() {
final int res =
- com.android.frameworks.servicestests.R.raw.input_port_associations_bad_displayport;
+ com.android.test.input.R.raw.input_port_associations_bad_displayport;
InputStream xml = mContext.getResources().openRawResource(res);
Map<String, Integer> associations = null;
try {
@@ -79,7 +79,7 @@
@Test
public void testGetInputPortAssociationsEmptyConfig() {
- final int res = com.android.frameworks.servicestests.R.raw.input_port_associations_bad_xml;
+ final int res = com.android.test.input.R.raw.input_port_associations_bad_xml;
InputStream xml = mContext.getResources().openRawResource(res);
try {
ConfigurationProcessor.processInputPortAssociations(xml);
diff --git a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
similarity index 94%
rename from services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
rename to tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index 498776d..93a5582 100644
--- a/services/tests/servicestests/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -20,6 +20,8 @@
import android.content.Context
import android.content.ContextWrapper
import android.hardware.display.DisplayViewport
+import android.hardware.input.InputManager
+import android.hardware.input.InputManagerGlobal
import android.os.IInputConstants
import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
@@ -27,9 +29,10 @@
import android.test.mock.MockContentResolver
import android.view.Display
import android.view.PointerIcon
-import androidx.test.InstrumentationRegistry
+import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.util.test.FakeSettingsProvider
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -59,7 +62,7 @@
* Tests for {@link InputManagerService}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:InputManagerServiceTests
+ * atest InputTests:InputManagerServiceTests
*/
@Presubmit
class InputManagerServiceTests {
@@ -84,10 +87,11 @@
private lateinit var context: Context
private lateinit var testLooper: TestLooper
private lateinit var contentResolver: MockContentResolver
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
@Before
fun setup() {
- context = spy(ContextWrapper(InstrumentationRegistry.getContext()))
+ context = spy(ContextWrapper(InstrumentationRegistry.getInstrumentation().getContext()))
contentResolver = MockContentResolver(context)
contentResolver.addProvider(Settings.AUTHORITY, FakeSettingsProvider())
whenever(context.contentResolver).thenReturn(contentResolver)
@@ -105,10 +109,22 @@
localService = service!!
}
})
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(service)
+ val inputManager = InputManager(context)
+ whenever(context.getSystemService(InputManager::class.java)).thenReturn(inputManager)
+ whenever(context.getSystemService(Context.INPUT_SERVICE)).thenReturn(inputManager)
+
assertTrue("Local service must be registered", this::localService.isInitialized)
service.setWindowManagerCallbacks(wmCallbacks)
}
+ @After
+ fun tearDown() {
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
+ }
+
@Test
fun testStart() {
verifyZeroInteractions(native)
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt b/tests/Input/src/com/android/server/input/KeyRemapperTests.kt
similarity index 94%
rename from services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt
rename to tests/Input/src/com/android/server/input/KeyRemapperTests.kt
index c10f651..f74fd72 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyRemapperTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyRemapperTests.kt
@@ -54,7 +54,7 @@
* Tests for {@link KeyRemapper}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:KeyRemapperTests
+ * atest InputTests:KeyRemapperTests
*/
@Presubmit
class KeyRemapperTests {
@@ -81,6 +81,7 @@
private lateinit var context: Context
private lateinit var dataStore: PersistentDataStore
private lateinit var testLooper: TestLooper
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
@Before
fun setup() {
@@ -103,7 +104,7 @@
dataStore,
testLooper.looper
)
- InputManagerGlobal.resetInstance(iInputManager)
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
val inputManager = InputManager(context)
Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
.thenReturn(inputManager)
@@ -112,7 +113,9 @@
@After
fun tearDown() {
- InputManagerGlobal.clearInstance()
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
rename to tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
index 3f4a4fb..59aa96c 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt
@@ -87,7 +87,7 @@
* Tests for {@link KeyboardBacklightController}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:KeyboardBacklightControllerTests
+ * atest InputTests:KeyboardBacklightControllerTests
*/
@Presubmit
class KeyboardBacklightControllerTests {
@@ -111,6 +111,7 @@
private lateinit var context: Context
private lateinit var dataStore: PersistentDataStore
private lateinit var testLooper: TestLooper
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
private var lightColorMap: HashMap<Int, Int> = HashMap()
private var lastBacklightState: KeyboardBacklightState? = null
private var sysfsNodeChanges = 0
@@ -133,7 +134,7 @@
testLooper = TestLooper()
keyboardBacklightController = KeyboardBacklightController(context, native, dataStore,
testLooper.looper, FakeAnimatorFactory(), uEventManager)
- InputManagerGlobal.resetInstance(iInputManager)
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
val inputManager = InputManager(context)
`when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager)
`when`(iInputManager.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID))
@@ -153,7 +154,9 @@
@After
fun tearDown() {
- InputManagerGlobal.clearInstance()
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
rename to tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index 55c45df..b6477510 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -37,6 +37,7 @@
import android.view.inputmethod.InputMethodSubtype
import androidx.test.core.R
import androidx.test.core.app.ApplicationProvider
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
@@ -77,7 +78,7 @@
* Tests for {@link Default UI} and {@link New UI}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:KeyboardLayoutManagerTests
+ * atest InputTests:KeyboardLayoutManagerTests
*/
@Presubmit
class KeyboardLayoutManagerTests {
@@ -120,6 +121,7 @@
private lateinit var context: Context
private lateinit var dataStore: PersistentDataStore
private lateinit var testLooper: TestLooper
+ private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
// Devices
private lateinit var keyboardDevice: InputDevice
@@ -130,6 +132,7 @@
@Before
fun setup() {
context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+ inputManagerGlobalSession = InputManagerGlobal.createTestSession(iInputManager)
dataStore = PersistentDataStore(object : PersistentDataStore.Injector() {
override fun openRead(): InputStream? {
throw FileNotFoundException()
@@ -148,8 +151,14 @@
setupIme()
}
+ @After
+ fun tearDown() {
+ if (this::inputManagerGlobalSession.isInitialized) {
+ inputManagerGlobalSession.close()
+ }
+ }
+
private fun setupInputDevices() {
- InputManagerGlobal.resetInstance(iInputManager)
val inputManager = InputManager(context)
Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
.thenReturn(inputManager)
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardMetricsCollectorTests.kt b/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
rename to tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
index c9724a3..e2dc131 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyboardMetricsCollectorTests.kt
@@ -58,7 +58,7 @@
* Tests for {@link KeyboardMetricsCollector}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:KeyboardMetricsCollectorTests
+ * atest InputTests:KeyboardMetricsCollectorTests
*/
@Presubmit
class KeyboardMetricsCollectorTests {
diff --git a/tests/InputMethodStressTest/TEST_MAPPING b/tests/InputMethodStressTest/TEST_MAPPING
index 06e2ce8..d982dd8 100644
--- a/tests/InputMethodStressTest/TEST_MAPPING
+++ b/tests/InputMethodStressTest/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "presubmit-large": [
+ "postsubmit": [
{
"name": "InputMethodStressTest"
}
diff --git a/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
index a8815dc..6a6ab00 100644
--- a/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
+++ b/tests/testables/src/com/android/internal/config/sysui/TestableFlagResolver.java
@@ -27,7 +27,9 @@
return mOverrides.getOrDefault(flag.mSysPropKey, flag.mDefaultValue);
}
- public void setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag, boolean isEnabled) {
+ public TestableFlagResolver setFlagOverride(SystemUiSystemPropertiesFlags.Flag flag,
+ boolean isEnabled) {
mOverrides.put(flag.mSysPropKey, isEnabled);
+ return this;
}
}