Merge "Logging for fields added in KeyboardConfigured atom" into udc-qpr-dev
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 70c3d7a..f33d299 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/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4c90d7b..41c58ef 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4230,21 +4230,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/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index 3d6ab6f..9a818e4 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -20,6 +20,7 @@
import android.app.GameModeInfo;
import android.app.GameState;
import android.app.IGameModeListener;
+import android.app.IGameStateListener;
/**
* @hide
@@ -49,4 +50,6 @@
void addGameModeListener(IGameModeListener gameModeListener);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
void removeGameModeListener(IGameModeListener gameModeListener);
+ void addGameStateListener(IGameStateListener gameStateListener);
+ void removeGameStateListener(IGameStateListener gameStateListener);
}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/core/java/android/app/IGameStateListener.aidl
similarity index 70%
rename from packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
rename to core/java/android/app/IGameStateListener.aidl
index dd89441..34cff48 100644
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
+++ b/core/java/android/app/IGameStateListener.aidl
@@ -14,10 +14,14 @@
* 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;
+package android.app;
+
+import android.app.GameState;
+
+/** @hide */
+interface IGameStateListener {
+ /**
+ * Called when the state of the game has changed.
+ */
+ oneway void onGameStateChanged(String packageName, in GameState state, int userId);
+}
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/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 99b297a..0e45787 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -283,7 +283,8 @@
* @see StreamConfigurationMap#getInputFormats
* @see StreamConfigurationMap#getInputSizes
* @see StreamConfigurationMap#getValidOutputFormatsForInput
- * @see StreamConfigurationMap#getOutputSizes
+ * @see StreamConfigurationMap#getOutputSizes(int)
+ * @see StreamConfigurationMap#getOutputSizes(Class)
* @see android.media.ImageWriter
* @see android.media.ImageReader
* @deprecated Please use {@link
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index a098362..c2fe080 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -130,14 +130,17 @@
/**
* Enable physical camera availability callbacks when the logical camera is unavailable
*
- * <p>Previously once a logical camera becomes unavailable, no {@link
- * #onPhysicalCameraAvailable} or {@link #onPhysicalCameraUnavailable} will be called until
- * the logical camera becomes available again. The results in the app opening the logical
- * camera not able to receive physical camera availability change.</p>
+ * <p>Previously once a logical camera becomes unavailable, no
+ * {@link AvailabilityCallback#onPhysicalCameraAvailable} or
+ * {@link AvailabilityCallback#onPhysicalCameraUnavailable} will
+ * be called until the logical camera becomes available again. The
+ * results in the app opening the logical camera not able to
+ * receive physical camera availability change.</p>
*
- * <p>With this change, the {@link #onPhysicalCameraAvailable} and {@link
- * #onPhysicalCameraUnavailable} can still be called while the logical camera is unavailable.
- * </p>
+ * <p>With this change, the {@link
+ * AvailabilityCallback#onPhysicalCameraAvailable} and {@link
+ * AvailabilityCallback#onPhysicalCameraUnavailable} can still be
+ * called while the logical camera is unavailable. </p>
*/
@ChangeId
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
diff --git a/core/java/android/hardware/camera2/package.html b/core/java/android/hardware/camera2/package.html
index 719c2f6..3fd5d7c 100644
--- a/core/java/android/hardware/camera2/package.html
+++ b/core/java/android/hardware/camera2/package.html
@@ -62,12 +62,28 @@
done with {@link android.media.ImageReader} with the {@link
android.graphics.ImageFormat#JPEG} and {@link
android.graphics.ImageFormat#RAW_SENSOR} formats. Application-driven
-processing of camera data in RenderScript, OpenGL ES, or directly in
-managed or native code is best done through {@link
-android.renderscript.Allocation} with a YUV {@link
-android.renderscript.Type}, {@link android.graphics.SurfaceTexture},
-and {@link android.media.ImageReader} with a {@link
-android.graphics.ImageFormat#YUV_420_888} format, respectively.</p>
+processing of camera data in OpenGL ES, or directly in managed or
+native code is best done through {@link
+android.graphics.SurfaceTexture}, or {@link android.media.ImageReader}
+with a {@link android.graphics.ImageFormat#YUV_420_888} format,
+respectively. </p>
+
+<p>By default, YUV-format buffers provided by the camera are using the
+JFIF YUV<->RGB transform matrix (equivalent to Rec.601 full-range
+encoding), and after conversion to RGB with this matrix, the resulting
+RGB data is in the sRGB colorspace. Captured JPEG images may contain
+an ICC profile to specify their color space information; if not, they
+should be assumed to be in the sRGB space as well. On some devices,
+the output colorspace can be changed via {@link
+android.hardware.camera2.params.SessionConfiguration#setColorSpace}.
+</p>
+<p>
+Note that although the YUV->RGB transform is the JFIF matrix (Rec.601
+full-range), due to legacy and compatibility reasons, the output is in
+the sRGB colorspace, which uses the Rec.709 color primaries. Image
+processing code can safely treat the output RGB as being in the sRGB
+colorspace.
+</p>
<p>The application then needs to construct a {@link
android.hardware.camera2.CaptureRequest}, which defines all the
diff --git a/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java b/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
index 2e3af80..bb154a9 100644
--- a/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
@@ -192,7 +192,7 @@
* @see OutputConfiguration#setDynamicRangeProfile
* @see SessionConfiguration#setColorSpace
* @see ColorSpace.Named
- * @see DynamicRangeProfiles.Profile
+ * @see DynamicRangeProfiles
*/
public @NonNull Set<Long> getSupportedDynamicRangeProfiles(@NonNull ColorSpace.Named colorSpace,
@ImageFormat.Format int imageFormat) {
@@ -230,7 +230,7 @@
* @see SessionConfiguration#setColorSpace
* @see OutputConfiguration#setDynamicRangeProfile
* @see ColorSpace.Named
- * @see DynamicRangeProfiles.Profile
+ * @see DynamicRangeProfiles
*/
public @NonNull Set<ColorSpace.Named> getSupportedColorSpacesForDynamicRange(
@ImageFormat.Format int imageFormat,
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
index 80db38f..d4ce0eb 100644
--- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -45,7 +45,7 @@
* Immutable class to store the recommended stream configurations to set up
* {@link android.view.Surface Surfaces} for creating a
* {@link android.hardware.camera2.CameraCaptureSession capture session} with
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)}.
*
* <p>The recommended list does not replace or deprecate the exhaustive complete list found in
* {@link StreamConfigurationMap}. It is a suggestion about available power and performance
@@ -70,7 +70,7 @@
* }</code></pre>
*
* @see CameraCharacteristics#getRecommendedStreamConfigurationMap
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public final class RecommendedStreamConfigurationMap {
@@ -282,7 +282,7 @@
/**
* Determine whether or not output surfaces with a particular user-defined format can be passed
- * {@link CameraDevice#createCaptureSession createCaptureSession}.
+ * {@link CameraDevice#createCaptureSession(SessionConfiguration) createCaptureSession}.
*
* <p>
* For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
@@ -292,7 +292,7 @@
* @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
* @return
* {@code true} if using a {@code surface} with this {@code format} will be
- * supported with {@link CameraDevice#createCaptureSession}
+ * supported with {@link CameraDevice#createCaptureSession(SessionConfiguration)}
*
* @throws IllegalArgumentException
* if the image format was not a defined named constant
@@ -508,8 +508,10 @@
}
/**
- * Determine whether or not the {@code surface} in its current state is suitable to be included
- * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ * Determine whether or not the {@code surface} in its current
+ * state is suitable to be included in a {@link
+ * CameraDevice#createCaptureSession(SessionConfiguration) capture
+ * session} as an output.
*
* <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
* </p>
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index 385f107..8f611a8 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -55,7 +55,7 @@
* at regular non high speed FPS ranges and optionally {@link InputConfiguration} for
* reprocessable sessions.
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see CameraDevice#createReprocessableCaptureSession
*/
public static final int SESSION_REGULAR = CameraDevice.SESSION_OPERATION_MODE_NORMAL;
@@ -110,10 +110,7 @@
*
* @see #SESSION_REGULAR
* @see #SESSION_HIGH_SPEED
- * @see CameraDevice#createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)
- * @see CameraDevice#createCaptureSessionByOutputConfigurations
- * @see CameraDevice#createReprocessableCaptureSession
- * @see CameraDevice#createConstrainedHighSpeedCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public SessionConfiguration(@SessionMode int sessionType,
@NonNull List<OutputConfiguration> outputs,
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index aabe149..ef0db7f 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -41,7 +41,7 @@
* {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP configurations} to set up
* {@link android.view.Surface Surfaces} for creating a
* {@link android.hardware.camera2.CameraCaptureSession capture session} with
- * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)}.
* <!-- TODO: link to input stream configuration -->
*
* <p>This is the authoritative list for all <!-- input/ -->output formats (and sizes respectively
@@ -62,7 +62,7 @@
* }</code></pre>
*
* @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public final class StreamConfigurationMap {
@@ -456,7 +456,7 @@
/**
* Determine whether or not output surfaces with a particular user-defined format can be passed
- * {@link CameraDevice#createCaptureSession createCaptureSession}.
+ * {@link CameraDevice#createCaptureSession(SessionConfiguration) createCaptureSession}.
*
* <p>This method determines that the output {@code format} is supported by the camera device;
* each output {@code surface} target may or may not itself support that {@code format}.
@@ -468,7 +468,7 @@
* @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
* @return
* {@code true} iff using a {@code surface} with this {@code format} will be
- * supported with {@link CameraDevice#createCaptureSession}
+ * supported with {@link CameraDevice#createCaptureSession(SessionConfiguration)}
*
* @throws IllegalArgumentException
* if the image format was not a defined named constant
@@ -476,7 +476,7 @@
*
* @see ImageFormat
* @see PixelFormat
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
*/
public boolean isOutputSupportedFor(int format) {
checkArgumentFormat(format);
@@ -521,7 +521,7 @@
*
* <p>Generally speaking this means that creating a {@link Surface} from that class <i>may</i>
* provide a producer endpoint that is suitable to be used with
- * {@link CameraDevice#createCaptureSession}.</p>
+ * {@link CameraDevice#createCaptureSession(SessionConfiguration)}.</p>
*
* <p>Since not all of the above classes support output of all format and size combinations,
* the particular combination should be queried with {@link #isOutputSupportedFor(Surface)}.</p>
@@ -531,7 +531,7 @@
*
* @throws NullPointerException if {@code klass} was {@code null}
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see #isOutputSupportedFor(Surface)
*/
public static <T> boolean isOutputSupportedFor(Class<T> klass) {
@@ -555,8 +555,10 @@
}
/**
- * Determine whether or not the {@code surface} in its current state is suitable to be included
- * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ * Determine whether or not the {@code surface} in its current
+ * state is suitable to be included in a {@link
+ * CameraDevice#createCaptureSession(SessionConfiguration) capture
+ * session} as an output.
*
* <p>Not all surfaces are usable with the {@link CameraDevice}, and not all configurations
* of that {@code surface} are compatible. Some classes that provide the {@code surface} are
@@ -588,7 +590,7 @@
* @throws NullPointerException if {@code surface} was {@code null}
* @throws IllegalArgumentException if the Surface endpoint is no longer valid
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see #isOutputSupportedFor(Class)
*/
public boolean isOutputSupportedFor(Surface surface) {
@@ -623,14 +625,16 @@
}
/**
- * Determine whether or not the particular stream configuration is suitable to be included
- * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ * Determine whether or not the particular stream configuration is
+ * suitable to be included in a {@link
+ * CameraDevice#createCaptureSession(SessionConfiguration) capture
+ * session} as an output.
*
* @param size stream configuration size
* @param format stream configuration format
* @return {@code true} if this is supported, {@code false} otherwise
*
- * @see CameraDevice#createCaptureSession
+ * @see CameraDevice#createCaptureSession(SessionConfiguration)
* @see #isOutputSupportedFor(Class)
* @hide
*/
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a9c4818..e472a40 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -103,11 +103,10 @@
import android.util.Printer;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
-import android.view.BatchedInputEventReceiver.SimpleBatchedInputEventReceiver;
-import android.view.Choreographer;
import android.view.Gravity;
import android.view.InputChannel;
import android.view.InputDevice;
+import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -1052,17 +1051,22 @@
stylusEvents.forEach(InputMethodService.this::onStylusHandwritingMotionEvent);
// create receiver for channel
- mHandwritingEventReceiver = new SimpleBatchedInputEventReceiver(
- channel,
- Looper.getMainLooper(), Choreographer.getInstance(),
- event -> {
+ mHandwritingEventReceiver = new InputEventReceiver(channel, Looper.getMainLooper()) {
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = false;
+ try {
if (!(event instanceof MotionEvent)) {
- return false;
+ return;
}
onStylusHandwritingMotionEvent((MotionEvent) event);
scheduleHandwritingSessionTimeout();
- return true;
- });
+ handled = true;
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+ };
scheduleHandwritingSessionTimeout();
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 3da696a..7fbaf10 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -882,10 +882,11 @@
}
static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
return new OpaqueUri(
- parcel.readString8(),
- Part.readFrom(parcel),
- Part.readFrom(parcel)
+ stringUri.parseScheme(),
+ stringUri.getSsp(),
+ stringUri.getFragmentPart()
);
}
@@ -895,9 +896,7 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- ssp.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
@@ -1196,22 +1195,25 @@
Part query, Part fragment) {
this.scheme = scheme;
this.authority = Part.nonNull(authority);
- this.path = path == null ? PathPart.NULL : path;
+ this.path = generatePath(path);
this.query = Part.nonNull(query);
this.fragment = Part.nonNull(fragment);
}
- static Uri readFrom(Parcel parcel) {
- final String scheme = parcel.readString8();
- final Part authority = Part.readFrom(parcel);
+ private PathPart generatePath(PathPart originalPath) {
// In RFC3986 the path should be determined based on whether there is a scheme or
// authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3).
final boolean hasSchemeOrAuthority =
(scheme != null && scheme.length() > 0) || !authority.isEmpty();
- final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel);
- final Part query = Part.readFrom(parcel);
- final Part fragment = Part.readFrom(parcel);
- return new HierarchicalUri(scheme, authority, path, query, fragment);
+ final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath)
+ : originalPath;
+ return newPath == null ? PathPart.NULL : newPath;
+ }
+
+ static Uri readFrom(Parcel parcel) {
+ final StringUri stringUri = new StringUri(parcel.readString8());
+ return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(),
+ stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart());
}
public int describeContents() {
@@ -1220,11 +1222,7 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID);
- parcel.writeString8(scheme);
- authority.writeTo(parcel);
- path.writeTo(parcel);
- query.writeTo(parcel);
- fragment.writeTo(parcel);
+ parcel.writeString8(toString());
}
public boolean isHierarchical() {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 7664bad..e6bdfe1 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -112,17 +112,9 @@
private static final int ANGLE_GL_DRIVER_ALL_ANGLE_OFF = 0;
// Values for ANGLE_GL_DRIVER_SELECTION_VALUES
- private enum AngleDriverChoice {
- DEFAULT("default"),
- ANGLE("angle"),
- NATIVE("native");
-
- public final String choice;
-
- AngleDriverChoice(String choice) {
- this.choice = choice;
- }
- }
+ 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 static final String PROPERTY_RO_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
@@ -203,16 +195,15 @@
}
/**
- * Query to determine the ANGLE driver choice.
+ * Query to determine if ANGLE should be used
*/
- private AngleDriverChoice queryAngleChoice(Context context, Bundle coreSettings,
- String packageName) {
+ private boolean shouldUseAngle(Context context, Bundle coreSettings, String packageName) {
if (TextUtils.isEmpty(packageName)) {
Log.v(TAG, "No package name specified; use the system driver");
- return AngleDriverChoice.DEFAULT;
+ return false;
}
- return queryAngleChoiceInternal(context, coreSettings, packageName);
+ return shouldUseAngleInternal(context, coreSettings, packageName);
}
private int getVulkanVersion(PackageManager pm) {
@@ -433,11 +424,10 @@
* forces a choice;
* 3) Use ANGLE if isAngleEnabledByGameMode() returns true;
*/
- private AngleDriverChoice queryAngleChoiceInternal(Context context, Bundle bundle,
- String packageName) {
+ private boolean shouldUseAngleInternal(Context context, Bundle bundle, String packageName) {
// Make sure we have a good package name
if (TextUtils.isEmpty(packageName)) {
- return AngleDriverChoice.DEFAULT;
+ return false;
}
// Check the semi-global switch (i.e. once system has booted enough) for whether ANGLE
@@ -452,7 +442,7 @@
}
if (allUseAngle == ANGLE_GL_DRIVER_ALL_ANGLE_ON) {
Log.v(TAG, "Turn on ANGLE for all applications.");
- return AngleDriverChoice.ANGLE;
+ return true;
}
// Get the per-application settings lists
@@ -475,7 +465,7 @@
+ optInPackages.size() + ", "
+ "number of values: "
+ optInValues.size());
- return mEnabledByGameMode ? AngleDriverChoice.ANGLE : AngleDriverChoice.DEFAULT;
+ return mEnabledByGameMode;
}
// See if this application is listed in the per-application settings list
@@ -483,7 +473,7 @@
if (pkgIndex < 0) {
Log.v(TAG, packageName + " is not listed in per-application setting");
- return mEnabledByGameMode ? AngleDriverChoice.ANGLE : AngleDriverChoice.DEFAULT;
+ return mEnabledByGameMode;
}
mAngleOptInIndex = pkgIndex;
@@ -493,14 +483,14 @@
Log.v(TAG,
"ANGLE Developer option for '" + packageName + "' "
+ "set to: '" + optInValue + "'");
- if (optInValue.equals(AngleDriverChoice.ANGLE.choice)) {
- return AngleDriverChoice.ANGLE;
- } else if (optInValue.equals(AngleDriverChoice.NATIVE.choice)) {
- return AngleDriverChoice.NATIVE;
+ if (optInValue.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE)) {
+ return true;
+ } else if (optInValue.equals(ANGLE_GL_DRIVER_CHOICE_NATIVE)) {
+ return false;
} else {
// The user either chose default or an invalid value; go with the default driver or what
// the game mode indicates
- return mEnabledByGameMode ? AngleDriverChoice.ANGLE : AngleDriverChoice.DEFAULT;
+ return mEnabledByGameMode;
}
}
@@ -568,13 +558,7 @@
private boolean setupAngle(Context context, Bundle bundle, PackageManager packageManager,
String packageName) {
- final AngleDriverChoice angleDriverChoice = queryAngleChoice(context, bundle, packageName);
- if (angleDriverChoice == AngleDriverChoice.DEFAULT) {
- return false;
- }
-
- if (queryAngleChoice(context, bundle, packageName) == AngleDriverChoice.NATIVE) {
- nativeSetAngleInfo("", true, packageName, null);
+ if (!shouldUseAngle(context, bundle, packageName)) {
return false;
}
@@ -643,10 +627,10 @@
Log.d(TAG, "ANGLE package libs: " + paths);
}
- // If we make it to here, ANGLE apk will be used. Call nativeSetAngleInfo() with the
- // application package name and ANGLE features to use.
+ // If we make it to here, ANGLE will be used. Call setAngleInfo() with the package name,
+ // and features to use.
final String[] features = getAngleEglFeatures(context, bundle);
- nativeSetAngleInfo(paths, false, packageName, features);
+ setAngleInfo(paths, false, packageName, features);
return true;
}
@@ -668,10 +652,10 @@
return false;
}
- // If we make it to here, system ANGLE will be used. Call nativeSetAngleInfo() with
- // the application package name and ANGLE features to use.
+ // If we make it to here, ANGLE will be used. Call setAngleInfo() with the package name,
+ // and features to use.
final String[] features = getAngleEglFeatures(context, bundle);
- nativeSetAngleInfo("system", false, packageName, features);
+ setAngleInfo("", true, packageName, features);
return true;
}
@@ -952,8 +936,8 @@
private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
- private static native void nativeSetAngleInfo(String path, boolean useNativeDriver,
- String packageName, String[] features);
+ private static native void setAngleInfo(String path, boolean useSystemAngle, String packageName,
+ String[] features);
private static native boolean setInjectLayersPrSetDumpable();
private static native void nativeToggleAngleAsSystemDriver(boolean enabled);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 820f454..753349c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2186,6 +2186,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}.
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/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 0071a0d..827600c 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -149,6 +149,13 @@
*/
public static final String SETTINGS_BIOMETRICS2_ENROLLMENT = "settings_biometrics2_enrollment";
+ /**
+ * Flag to enable/disable FingerprintSettings v2
+ * @hide
+ */
+ public static final String SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS =
+ "settings_biometrics2_fingerprint";
+
/** Flag to enable/disable entire page in Accessibility -> Hearing aids
* @hide
*/
@@ -239,6 +246,7 @@
DEFAULT_FLAGS.put(SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, "true");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API, "true");
DEFAULT_FLAGS.put(SETTINGS_REMOTE_DEVICE_CREDENTIAL_VALIDATION, "true");
+ DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_FINGERPRINT_SETTINGS, "false");
}
private static final Set<String> PERSISTENT_FLAGS;
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/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/View.java b/core/java/android/view/View.java
index f1cde3b..2499be9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -21821,6 +21821,8 @@
mCurrentAnimation = null;
if ((mViewFlags & TOOLTIP) == TOOLTIP) {
+ removeCallbacks(mTooltipInfo.mShowTooltipRunnable);
+ removeCallbacks(mTooltipInfo.mHideTooltipRunnable);
hideTooltip();
}
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/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/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3f308e6..b323314 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -50,6 +50,7 @@
import android.annotation.UiThread;
import android.annotation.UserIdInt;
import android.app.ActivityThread;
+import android.app.PropertyInvalidatedCache;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
@@ -536,6 +537,13 @@
@UnsupportedAppUsage
Rect mCursorRect = new Rect();
+ /** Cached value for {@link #isStylusHandwritingAvailable} for userId. */
+ @GuardedBy("mH")
+ private PropertyInvalidatedCache<Integer, Boolean> mStylusHandwritingAvailableCache;
+
+ private static final String CACHE_KEY_STYLUS_HANDWRITING_PROPERTY =
+ "cache_key.system_server.stylus_handwriting";
+
@GuardedBy("mH")
private int mCursorSelStart;
@GuardedBy("mH")
@@ -662,6 +670,15 @@
private static final int MSG_UPDATE_VIRTUAL_DISPLAY_TO_SCREEN_MATRIX = 30;
private static final int MSG_ON_SHOW_REQUESTED = 31;
+ /**
+ * Calling this will invalidate Local stylus handwriting availability Cache which
+ * forces the next query in any process to recompute the cache.
+ * @hide
+ */
+ public static void invalidateLocalStylusHandwritingAvailabilityCaches() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_STYLUS_HANDWRITING_PROPERTY);
+ }
+
private static boolean isAutofillUIShowing(View servedView) {
AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
return afm != null && afm.isAutofillUiShowing();
@@ -1577,8 +1594,21 @@
if (fallbackContext == null) {
return false;
}
-
- return IInputMethodManagerGlobalInvoker.isStylusHandwritingAvailableAsUser(userId);
+ boolean isAvailable;
+ synchronized (mH) {
+ if (mStylusHandwritingAvailableCache == null) {
+ mStylusHandwritingAvailableCache = new PropertyInvalidatedCache<>(
+ 4 /* maxEntries */, CACHE_KEY_STYLUS_HANDWRITING_PROPERTY) {
+ @Override
+ public Boolean recompute(Integer userId) {
+ return IInputMethodManagerGlobalInvoker.isStylusHandwritingAvailableAsUser(
+ userId);
+ }
+ };
+ }
+ isAvailable = mStylusHandwritingAvailableCache.query(userId);
+ }
+ return isAvailable;
}
/**
diff --git a/core/java/android/widget/RemoteViews.aidl b/core/java/android/widget/RemoteViews.aidl
index ec86410..6a5fc03 100644
--- a/core/java/android/widget/RemoteViews.aidl
+++ b/core/java/android/widget/RemoteViews.aidl
@@ -17,3 +17,4 @@
package android.widget;
parcelable RemoteViews;
+parcelable RemoteViews.RemoteCollectionItems;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index bd7f5a0..d9e76fe 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -33,16 +33,19 @@
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.app.Application;
import android.app.LoadedApk;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.appwidget.AppWidgetHostView;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentSender;
+import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.ColorStateList;
@@ -65,10 +68,12 @@
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.Process;
+import android.os.RemoteException;
import android.os.StrictMode;
import android.os.UserHandle;
import android.system.Os;
@@ -98,8 +103,10 @@
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.android.internal.R;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.util.Preconditions;
+import com.android.internal.widget.IRemoteViewsFactory;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
@@ -124,7 +131,9 @@
import java.util.Map;
import java.util.Objects;
import java.util.Stack;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -324,6 +333,13 @@
(clazz) -> clazz.isAnnotationPresent(RemoteViews.RemoteView.class);
/**
+ * The maximum waiting time for remote adapter conversion in milliseconds
+ *
+ * @hide
+ */
+ private static final int MAX_ADAPTER_CONVERSION_WAITING_TIME_MS = 2000;
+
+ /**
* Application that hosts the remote views.
*
* @hide
@@ -1042,28 +1058,96 @@
}
private class SetRemoteCollectionItemListAdapterAction extends Action {
- private final RemoteCollectionItems mItems;
+ private @NonNull CompletableFuture<RemoteCollectionItems> mItemsFuture;
- SetRemoteCollectionItemListAdapterAction(@IdRes int id, RemoteCollectionItems items) {
+ SetRemoteCollectionItemListAdapterAction(@IdRes int id,
+ @NonNull RemoteCollectionItems items) {
viewId = id;
- mItems = items;
- mItems.setHierarchyRootData(getHierarchyRootData());
+ items.setHierarchyRootData(getHierarchyRootData());
+ mItemsFuture = CompletableFuture.completedFuture(items);
+ }
+
+ SetRemoteCollectionItemListAdapterAction(@IdRes int id, Intent intent) {
+ viewId = id;
+ mItemsFuture = getItemsFutureFromIntentWithTimeout(intent);
+ setHierarchyRootData(getHierarchyRootData());
+ }
+
+ private static CompletableFuture<RemoteCollectionItems> getItemsFutureFromIntentWithTimeout(
+ Intent intent) {
+ if (intent == null) {
+ Log.e(LOG_TAG, "Null intent received when generating adapter future");
+ return CompletableFuture.completedFuture(new RemoteCollectionItems
+ .Builder().build());
+ }
+
+ final Context context = ActivityThread.currentApplication();
+ final CompletableFuture<RemoteCollectionItems> result = new CompletableFuture<>();
+
+ context.bindService(intent, Context.BindServiceFlags.of(Context.BIND_AUTO_CREATE),
+ result.defaultExecutor(), new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName componentName,
+ IBinder iBinder) {
+ RemoteCollectionItems items;
+ try {
+ items = IRemoteViewsFactory.Stub.asInterface(iBinder)
+ .getRemoteCollectionItems();
+ } catch (RemoteException re) {
+ items = new RemoteCollectionItems.Builder().build();
+ Log.e(LOG_TAG, "Error getting collection items from the factory",
+ re);
+ } finally {
+ context.unbindService(this);
+ }
+
+ result.complete(items);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName componentName) { }
+ });
+
+ result.completeOnTimeout(
+ new RemoteCollectionItems.Builder().build(),
+ MAX_ADAPTER_CONVERSION_WAITING_TIME_MS, TimeUnit.MILLISECONDS);
+
+ return result;
}
SetRemoteCollectionItemListAdapterAction(Parcel parcel) {
viewId = parcel.readInt();
- mItems = new RemoteCollectionItems(parcel, getHierarchyRootData());
+ mItemsFuture = CompletableFuture.completedFuture(
+ new RemoteCollectionItems(parcel, getHierarchyRootData()));
}
@Override
public void setHierarchyRootData(HierarchyRootData rootData) {
- mItems.setHierarchyRootData(rootData);
+ mItemsFuture = mItemsFuture
+ .thenApply(rc -> {
+ rc.setHierarchyRootData(rootData);
+ return rc;
+ });
+ }
+
+ private static RemoteCollectionItems getCollectionItemsFromFuture(
+ CompletableFuture<RemoteCollectionItems> itemsFuture) {
+ RemoteCollectionItems items;
+ try {
+ items = itemsFuture.get();
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Error getting collection items from future", e);
+ items = new RemoteCollectionItems.Builder().build();
+ }
+
+ return items;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(viewId);
- mItems.writeToParcel(dest, flags, /* attached= */ true);
+ RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture);
+ items.writeToParcel(dest, flags, /* attached= */ true);
}
@Override
@@ -1072,6 +1156,8 @@
View target = root.findViewById(viewId);
if (target == null) return;
+ RemoteCollectionItems items = getCollectionItemsFromFuture(mItemsFuture);
+
// Ensure that we are applying to an AppWidget root
if (!(rootParent instanceof AppWidgetHostView)) {
Log.e(LOG_TAG, "setRemoteAdapter can only be used for "
@@ -1092,10 +1178,10 @@
// recycling in setAdapter, so we must call setAdapter again if the number of view types
// increases.
if (adapter instanceof RemoteCollectionItemsAdapter
- && adapter.getViewTypeCount() >= mItems.getViewTypeCount()) {
+ && adapter.getViewTypeCount() >= items.getViewTypeCount()) {
try {
((RemoteCollectionItemsAdapter) adapter).setData(
- mItems, params.handler, params.colorResources);
+ items, params.handler, params.colorResources);
} catch (Throwable throwable) {
// setData should never failed with the validation in the items builder, but if
// it does, catch and rethrow.
@@ -1105,7 +1191,7 @@
}
try {
- adapterView.setAdapter(new RemoteCollectionItemsAdapter(mItems,
+ adapterView.setAdapter(new RemoteCollectionItemsAdapter(items,
params.handler, params.colorResources));
} catch (Throwable throwable) {
// This could throw if the AdapterView somehow doesn't accept BaseAdapter due to
@@ -4679,6 +4765,12 @@
* providing data to the RemoteViewsAdapter
*/
public void setRemoteAdapter(@IdRes int viewId, Intent intent) {
+ if (AppGlobals.getIntCoreSetting(
+ SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION,
+ SystemUiDeviceConfigFlags.REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT ? 1 : 0) == 1) {
+ addAction(new SetRemoteCollectionItemListAdapterAction(viewId, intent));
+ return;
+ }
addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
}
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index 214e5cc..d4f4d19 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -43,6 +43,13 @@
private static final Object sLock = new Object();
/**
+ * Used for determining the maximum number of entries to retrieve from RemoteViewsFactory
+ *
+ * @hide
+ */
+ private static final int MAX_NUM_ENTRY = 25;
+
+ /**
* An interface for an adapter between a remote collection view (ListView, GridView, etc) and
* the underlying data for that view. The implementor is responsible for making a RemoteView
* for each item in the data set. This interface is a thin wrapper around {@link Adapter}.
@@ -227,6 +234,30 @@
}
}
+ @Override
+ public RemoteViews.RemoteCollectionItems getRemoteCollectionItems() {
+ RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
+ .Builder().build();
+
+ try {
+ RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
+ new RemoteViews.RemoteCollectionItems.Builder();
+ mFactory.onDataSetChanged();
+
+ itemsBuilder.setHasStableIds(mFactory.hasStableIds());
+ final int numOfEntries = Math.min(mFactory.getCount(), MAX_NUM_ENTRY);
+ for (int i = 0; i < numOfEntries; i++) {
+ itemsBuilder.addItem(mFactory.getItemId(i), mFactory.getViewAt(i));
+ }
+
+ items = itemsBuilder.build();
+ } catch (Exception ex) {
+ Thread t = Thread.currentThread();
+ Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+ }
+ return items;
+ }
+
private RemoteViewsFactory mFactory;
private boolean mIsCreated;
}
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 27d8a8f..b74c879 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/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java
index 413f0cc..e153bb7 100644
--- a/core/java/android/window/TaskFragmentOperation.java
+++ b/core/java/android/window/TaskFragmentOperation.java
@@ -73,6 +73,13 @@
/** Sets the relative bounds with {@link WindowContainerTransaction#setRelativeBounds}. */
public static final int OP_TYPE_SET_RELATIVE_BOUNDS = 9;
+ /**
+ * Reorders the TaskFragment to be the front-most TaskFragment in the Task.
+ * Note that there could still have other WindowContainer on top of the front-most
+ * TaskFragment, such as a non-embedded Activity.
+ */
+ public static final int OP_TYPE_REORDER_TO_FRONT = 10;
+
@IntDef(prefix = { "OP_TYPE_" }, value = {
OP_TYPE_UNKNOWN,
OP_TYPE_CREATE_TASK_FRAGMENT,
@@ -84,7 +91,8 @@
OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT,
OP_TYPE_SET_COMPANION_TASK_FRAGMENT,
OP_TYPE_SET_ANIMATION_PARAMS,
- OP_TYPE_SET_RELATIVE_BOUNDS
+ OP_TYPE_SET_RELATIVE_BOUNDS,
+ OP_TYPE_REORDER_TO_FRONT
})
@Retention(RetentionPolicy.SOURCE)
public @interface OperationType {}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 9ffccb3..0ba271f 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -532,6 +532,17 @@
public static final String TASK_MANAGER_SHOW_FOOTER_DOT = "task_manager_show_footer_dot";
/**
+ * (boolean) Whether to enable the adapter conversion in RemoteViews
+ */
+ public static final String REMOTEVIEWS_ADAPTER_CONVERSION = "remoteviews_adapter_conversion";
+
+ /**
+ * Default value for whether the adapter conversion is enabled or not. This is set for
+ * RemoteViews and should not be a common practice.
+ */
+ public static final boolean REMOTEVIEWS_ADAPTER_CONVERSION_DEFAULT = false;
+
+ /**
* (boolean) Whether the task manager should show a stop button if the app is allowlisted
* by the user.
*/
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/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/IRemoteViewsFactory.aidl b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
index c06dab9..918d9c0 100644
--- a/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
+++ b/core/java/com/android/internal/widget/IRemoteViewsFactory.aidl
@@ -39,5 +39,6 @@
boolean hasStableIds();
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
boolean isCreated();
+ RemoteViews.RemoteCollectionItems getRemoteCollectionItems();
}
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/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 361bdce..e018393 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1082,7 +1082,10 @@
*/
@UnsupportedAppUsage
public boolean isVisiblePatternEnabled(int userId) {
- return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, false, userId);
+ // Default to true, since this gets explicitly set to true when a pattern is first set
+ // anyway, which makes true the user-visible default. The low-level default should be the
+ // same, in order for FRP credential verification to get the same default.
+ return getBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, true, userId);
}
/**
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index d068a3a..e2672f5 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -21,3 +21,6 @@
per-file ObservableTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
per-file RemeasuringLinearLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
per-file ViewClippingUtil.java = file:/services/core/java/com/android/server/notification/OWNERS
+
+# Appwidget related
+per-file *RemoteViews* = file:/services/appwidget/java/com/android/server/appwidget/OWNERS
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 8fc30d1..afc3cbd 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -50,7 +50,7 @@
appPackageNameChars.c_str(), vulkanVersion);
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jboolean useNativeDriver,
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jboolean useSystemAngle,
jstring packageName, jobjectArray featuresObj) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars packageNameChars(env, packageName);
@@ -73,7 +73,7 @@
}
}
- android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), useNativeDriver,
+ android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), useSystemAngle,
packageNameChars.c_str(), features);
}
@@ -118,7 +118,7 @@
reinterpret_cast<void*>(setGpuStats_native)},
{"setInjectLayersPrSetDumpable", "()Z",
reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
- {"nativeSetAngleInfo", "(Ljava/lang/String;ZLjava/lang/String;[Ljava/lang/String;)V",
+ {"setAngleInfo", "(Ljava/lang/String;ZLjava/lang/String;[Ljava/lang/String;)V",
reinterpret_cast<void*>(setAngleInfo_native)},
{"setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V",
reinterpret_cast<void*>(setLayerPaths_native)},
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_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/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a941dc7..208d5a6 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 f97768e..231f4b2 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 a812ac0..c71ee63 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/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>
@@ -2315,7 +2315,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 626c3d6..4c63a20 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 5a41074..6a9f5fe 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 1baf387..8e09389 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 f226b96..538e126 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/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>
@@ -2313,7 +2313,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 b4ba000..9b00b2c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 25c0d42..bf5ad8d1 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 e824ecc..ab8789c 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 46fc3a3..ac37eb1 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 196fa56..a517a18 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1396,7 +1396,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>
@@ -1953,7 +1953,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>
@@ -2313,7 +2313,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 c1f0e71..01ecd96 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 ad6cfbf..4430ef2 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 4ea1eab..d9051a4 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 675add9..1feb601 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 7b6ccf3..037c55d 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 a1c7872..cdf3677 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 7c467e8..8952bdc 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 4f6c120..749b2ff 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 9343060..56aaf5a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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>
@@ -2336,9 +2335,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 c0e705c..47cf2cc 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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>
@@ -2336,8 +2335,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 c50f3ba..3bd876f 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 51f41ef..5b7741f 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 b594258..ad027bc 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>
@@ -1394,7 +1394,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>
@@ -1640,7 +1640,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>
@@ -2311,7 +2311,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 edfae76..319193d 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 bca6087..ea51b7f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 221c526..a1d4383 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 39ae243..73527bf 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 703bb44..692b70d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 bfa4f39..8d41c04 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 d655dd4..817efed 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 e5efd16..1916a52 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 f831700..5491f34 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 92d85c7..0ff21cb 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 1c7f5b3..3ba7120 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 fe663dd..39076f7 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 1bba6e5..1dac705 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 64eb303..7f7104e 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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>
@@ -2337,7 +2336,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 e09aa15..8db1325 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 70f5828..df69e4c 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>
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 8647785..5328e58 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1042,7 +1042,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>
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 26aa63d..2ce4b8c 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 18fe689..3485cc5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 ede68e4..3a57229 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1007,7 +1007,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>
@@ -1015,7 +1015,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>
@@ -1394,7 +1394,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>
@@ -1666,7 +1666,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>
@@ -2311,7 +2311,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 b600d2e..0021677 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 e3f1952..8e43d8a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1396,7 +1396,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>
@@ -2313,7 +2313,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 d874fdd..2257c25 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 06a3530..21950c0 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1257,7 +1257,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>
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 0ca9b37..2dac3e4 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 8df63ec..8183577 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 432ffce..2144035 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 ec737c9..c800be9 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 2df17b4..d2f7ef7 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>
@@ -1394,7 +1394,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>
@@ -1952,7 +1952,7 @@
<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>
@@ -2311,7 +2311,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 f8c8aaa..f2c5c77 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 bbb1992..13c3c12 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 5457872..a9d654f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 6932b44..6215213 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>
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 0d0e0c8..dc53918 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 f72ff68..4e3fe0d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1396,7 +1396,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>
@@ -2313,7 +2313,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 72cb00e..47115ba 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 2158dfd..86e84ba 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 72cb00e..47115ba 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 b52c0eb..14b5b14 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1395,7 +1395,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>
@@ -1952,7 +1952,7 @@
<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>
@@ -2312,7 +2312,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 f8f323f..da1f520 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/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>
@@ -2313,7 +2313,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 a62caeb..c09d7f5 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 9c3c655..50e519d 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>
@@ -1396,7 +1396,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>
@@ -2313,7 +2313,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 f92a5bd..9a57ccf 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>
@@ -1396,7 +1396,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>
@@ -2313,7 +2313,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 512dbc7..ac6668d 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 ccd638e..2b6f900 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1395,7 +1395,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>
@@ -2312,7 +2312,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 4b5d45e..3701571 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 5e30e0d..5d948be 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 26442bf..702fb85 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 73aab58..63a9b21 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -657,7 +657,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>
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 916e857..9398393 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 786c324..3b2e788 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 a0c71b5..22899c7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1394,7 +1394,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>
@@ -1951,7 +1951,7 @@
<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>
@@ -2311,7 +2311,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 0c9f99a..e7b1d66 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -673,7 +673,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>
@@ -717,12 +717,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">
@@ -974,7 +974,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>
@@ -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>
@@ -2313,7 +2313,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 e1c2752..95122e9 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 93ad0ce..1080918 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 bfe1561..3101fac 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d7101f4..54221e4 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 a471a42..7e108937 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 1449ab6..5f6bc20 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1393,8 +1393,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>
@@ -2311,7 +2311,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 72b4404..43c0ada 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1394,7 +1394,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>
@@ -2311,7 +2311,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 3be0d7f..2d8bfbb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5574,13 +5574,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.
@@ -5605,7 +5605,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 24da59a..b129321 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/symbols.xml b/core/res/res/values/symbols.xml
index 85e9792..59306a3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2298,6 +2298,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" />
@@ -4945,7 +4946,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/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index b73a87c..4857741 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -884,12 +884,13 @@
mConfig.setTo(config);
++mNumOfConfigChanges;
- if (mConfigLatch != null) {
+ final CountDownLatch configLatch = mConfigLatch;
+ if (configLatch != null) {
if (mTestLatch != null) {
mTestLatch.countDown();
}
try {
- mConfigLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
+ configLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 89632a4..2a4ca79 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -25,8 +25,6 @@
import java.io.File;
import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -869,84 +867,90 @@
return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);
}
- /** Attempting to unparcel a legacy parcel format of Uri.{,Path}Part should fail. */
- public void testUnparcelLegacyPart_fails() throws Exception {
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$Part"));
- assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$PathPart"));
- }
-
- private static void assertUnparcelLegacyPart_fails(Class partClass) throws Exception {
- Parcel parcel = Parcel.obtain();
- parcel.writeInt(0 /* BOTH */);
- parcel.writeString("encoded");
- parcel.writeString("decoded");
- parcel.setDataPosition(0);
-
- Method readFromMethod = partClass.getDeclaredMethod("readFrom", Parcel.class);
- readFromMethod.setAccessible(true);
- try {
- readFromMethod.invoke(null, parcel);
- fail();
- } catch (InvocationTargetException expected) {
- Throwable targetException = expected.getTargetException();
- // Check that the exception was thrown for the correct reason.
- assertEquals("Unknown representation: 0", targetException.getMessage());
- } finally {
- parcel.recycle();
- }
- }
-
- private Uri buildUriFromRawParcel(boolean argumentsEncoded,
+ private Uri buildUriFromParts(boolean argumentsEncoded,
String scheme,
String authority,
String path,
String query,
String fragment) {
- // Representation value (from AbstractPart.REPRESENTATION_{ENCODED,DECODED}).
- final int representation = argumentsEncoded ? 1 : 2;
- Parcel parcel = Parcel.obtain();
- try {
- parcel.writeInt(3); // hierarchical
- parcel.writeString8(scheme);
- parcel.writeInt(representation);
- parcel.writeString8(authority);
- parcel.writeInt(representation);
- parcel.writeString8(path);
- parcel.writeInt(representation);
- parcel.writeString8(query);
- parcel.writeInt(representation);
- parcel.writeString8(fragment);
- parcel.setDataPosition(0);
- return Uri.CREATOR.createFromParcel(parcel);
- } finally {
- parcel.recycle();
+ final Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme);
+ if (argumentsEncoded) {
+ builder.encodedAuthority(authority);
+ builder.encodedPath(path);
+ builder.encodedQuery(query);
+ builder.encodedFragment(fragment);
+ } else {
+ builder.authority(authority);
+ builder.path(path);
+ builder.query(query);
+ builder.fragment(fragment);
}
+ return builder.build();
}
public void testUnparcelMalformedPath() {
// Regression tests for b/171966843.
// Test cases with arguments encoded (covering testing `scheme` * `authority` options).
- Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null);
+ Uri uri0 = buildUriFromParts(true, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/@evil.com", uri0.toString());
- Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x");
+ Uri uri1 = buildUriFromParts(true, null, "google.com", "@evil.com", "name=spark", "x");
assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString());
- Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null);
+ Uri uri2 = buildUriFromParts(true, "http:", null, "@evil.com", null, null);
assertEquals("http::/@evil.com", uri2.toString());
- Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null);
+ Uri uri3 = buildUriFromParts(true, null, null, "@evil.com", null, null);
assertEquals("@evil.com", uri3.toString());
// Test cases with arguments not encoded (covering testing `scheme` * `authority` options).
- Uri uriA = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null);
+ Uri uriA = buildUriFromParts(false, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/%40evil.com", uriA.toString());
- Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null);
+ Uri uriB = buildUriFromParts(false, null, "google.com", "@evil.com", null, null);
assertEquals("//google.com/%40evil.com", uriB.toString());
- Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null);
+ Uri uriC = buildUriFromParts(false, "http:", null, "@evil.com", null, null);
assertEquals("http::/%40evil.com", uriC.toString());
- Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y");
+ Uri uriD = buildUriFromParts(false, null, null, "@evil.com", "name=spark", "y");
assertEquals("%40evil.com?name%3Dspark#y", uriD.toString());
}
+ public void testParsedUriFromStringEquality() {
+ Uri uri = buildUriFromParts(
+ true, "https", "google.com", "@evil.com", null, null);
+ assertEquals(uri, Uri.parse(uri.toString()));
+ Uri uri2 = buildUriFromParts(
+ true, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri2, Uri.parse(uri2.toString()));
+ Uri uri3 = buildUriFromParts(
+ false, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
+ assertEquals(uri3, Uri.parse(uri3.toString()));
+ }
+
+ public void testParceledUrisAreEqual() {
+ Uri opaqueUri = Uri.fromParts("fake://uri#", "ssp", "fragment");
+ Parcel parcel = Parcel.obtain();
+ try {
+ opaqueUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+
+ Uri hierarchicalUri = new Uri.Builder().scheme("fake://uri#").authority("auth").build();
+ parcel = Parcel.obtain();
+ try {
+ hierarchicalUri.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
+ Uri parsedUri = Uri.parse(postParcelUri.toString());
+ assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
+ } finally {
+ parcel.recycle();
+ }
+ }
+
public void testToSafeString() {
checkToSafeString("tel:xxxxxx", "tel:Google");
checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
index 184b9eac..4f722ce 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsAdapterTest.java
@@ -353,6 +353,23 @@
public boolean isCreated() {
return false;
}
+
+ @Override
+ public RemoteViews.RemoteCollectionItems getRemoteCollectionItems() {
+ RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
+ new RemoteViews.RemoteCollectionItems.Builder();
+ itemsBuilder.setHasStableIds(hasStableIds())
+ .setViewTypeCount(getViewTypeCount());
+ try {
+ for (int i = 0; i < mCount; i++) {
+ itemsBuilder.addItem(getItemId(i), getViewAt(i));
+ }
+ } catch (RemoteException e) {
+ // No-op
+ }
+
+ return itemsBuilder.build();
+ }
}
private static class DistinctIntent extends Intent {
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/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 76e0e1e..55eabb0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -48,7 +48,7 @@
// TODO(b/241126279) Introduce constants to better version functionality
@Override
public int getVendorApiLevel() {
- return 3;
+ return 4;
}
@NonNull
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
index 18497ad..381e9d4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java
@@ -32,7 +32,7 @@
*/
class SplitContainer {
@NonNull
- private final TaskFragmentContainer mPrimaryContainer;
+ private TaskFragmentContainer mPrimaryContainer;
@NonNull
private final TaskFragmentContainer mSecondaryContainer;
@NonNull
@@ -46,17 +46,35 @@
@NonNull
private final IBinder mToken;
+ /**
+ * Whether the selection of which container is primary can be changed at runtime. Runtime
+ * updates is currently possible only for {@link SplitPinContainer}
+ *
+ * @see SplitPinContainer
+ */
+ private final boolean mIsPrimaryContainerMutable;
+
SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
@NonNull Activity primaryActivity,
@NonNull TaskFragmentContainer secondaryContainer,
@NonNull SplitRule splitRule,
@NonNull SplitAttributes splitAttributes) {
+ this(primaryContainer, primaryActivity, secondaryContainer, splitRule, splitAttributes,
+ false /* isPrimaryContainerMutable */);
+ }
+
+ SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull Activity primaryActivity,
+ @NonNull TaskFragmentContainer secondaryContainer,
+ @NonNull SplitRule splitRule,
+ @NonNull SplitAttributes splitAttributes, boolean isPrimaryContainerMutable) {
mPrimaryContainer = primaryContainer;
mSecondaryContainer = secondaryContainer;
mSplitRule = splitRule;
mDefaultSplitAttributes = splitRule.getDefaultSplitAttributes();
mCurrentSplitAttributes = splitAttributes;
mToken = new Binder("SplitContainer");
+ mIsPrimaryContainerMutable = isPrimaryContainerMutable;
if (shouldFinishPrimaryWithSecondary(splitRule)) {
if (mPrimaryContainer.getRunningActivityCount() == 1
@@ -74,6 +92,13 @@
}
}
+ void setPrimaryContainer(@NonNull TaskFragmentContainer primaryContainer) {
+ if (!mIsPrimaryContainerMutable) {
+ throw new IllegalStateException("Cannot update primary TaskFragmentContainer");
+ }
+ mPrimaryContainer = primaryContainer;
+ }
+
@NonNull
TaskFragmentContainer getPrimaryContainer() {
return mPrimaryContainer;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 4cedd41..a2f75e0 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -213,6 +213,56 @@
}
@Override
+ public boolean pinTopActivityStack(int taskId, @NonNull SplitPinRule splitPinRule) {
+ synchronized (mLock) {
+ final TaskContainer task = getTaskContainer(taskId);
+ if (task == null) {
+ Log.e(TAG, "Cannot find the task for id: " + taskId);
+ return false;
+ }
+
+ final TaskFragmentContainer topContainer =
+ task.getTopNonFinishingTaskFragmentContainer();
+ // Cannot pin the TaskFragment if no other TaskFragment behind it.
+ if (topContainer == null || task.indexOf(topContainer) <= 0) {
+ Log.w(TAG, "Cannot find an ActivityStack to pin or split");
+ return false;
+ }
+ // Abort if the top container is already pinned.
+ if (task.getSplitPinContainer() != null) {
+ Log.w(TAG, "There is already a pinned ActivityStack.");
+ return false;
+ }
+
+ // Find a valid adjacent TaskFragmentContainer
+ final TaskFragmentContainer primaryContainer =
+ task.getNonFinishingTaskFragmentContainerBelow(topContainer);
+ if (primaryContainer == null) {
+ Log.w(TAG, "Cannot find another ActivityStack to split");
+ return false;
+ }
+
+ // Registers a Split
+ final SplitPinContainer splitPinContainer = new SplitPinContainer(primaryContainer,
+ topContainer, splitPinRule, splitPinRule.getDefaultSplitAttributes());
+ task.addSplitContainer(splitPinContainer);
+
+ // Updates the Split
+ final TransactionRecord transactionRecord = mTransactionManager.startNewTransaction();
+ final WindowContainerTransaction wct = transactionRecord.getTransaction();
+ mPresenter.updateSplitContainer(splitPinContainer, wct);
+ transactionRecord.apply(false /* shouldApplyIndependently */);
+ updateCallbackIfNecessary();
+ return true;
+ }
+ }
+
+ @Override
+ public void unpinTopActivityStack(int taskId){
+ // TODO
+ }
+
+ @Override
public void setSplitAttributesCalculator(
@NonNull Function<SplitAttributesCalculatorParams, SplitAttributes> calculator) {
synchronized (mLock) {
@@ -672,7 +722,7 @@
if (targetContainer == null) {
// When there is no embedding rule matched, try to place it in the top container
// like a normal launch.
- targetContainer = taskContainer.getTopTaskFragmentContainer();
+ targetContainer = taskContainer.getTopNonFinishingTaskFragmentContainer();
}
if (targetContainer == null) {
return;
@@ -791,7 +841,8 @@
final TaskFragmentContainer container = getContainerWithActivity(activity);
if (!isOnReparent && container != null
- && container.getTaskContainer().getTopTaskFragmentContainer() != container) {
+ && container.getTaskContainer().getTopNonFinishingTaskFragmentContainer()
+ != container) {
// Do not resolve if the launched activity is not the top-most container in the Task.
return true;
}
@@ -888,7 +939,8 @@
if (taskContainer == null) {
return;
}
- final TaskFragmentContainer targetContainer = taskContainer.getTopTaskFragmentContainer();
+ final TaskFragmentContainer targetContainer =
+ taskContainer.getTopNonFinishingTaskFragmentContainer();
if (targetContainer == null) {
return;
}
@@ -1213,11 +1265,13 @@
// 3. Whether the top activity (if any) should be split with the new activity intent.
final TaskContainer taskContainer = getTaskContainer(taskId);
- if (taskContainer == null || taskContainer.getTopTaskFragmentContainer() == null) {
+ if (taskContainer == null
+ || taskContainer.getTopNonFinishingTaskFragmentContainer() == null) {
// There is no other activity in the Task to check split with.
return null;
}
- final TaskFragmentContainer topContainer = taskContainer.getTopTaskFragmentContainer();
+ final TaskFragmentContainer topContainer =
+ taskContainer.getTopNonFinishingTaskFragmentContainer();
final Activity topActivity = topContainer.getTopNonFinishingActivity();
if (topActivity != null && topActivity != launchingActivity) {
final TaskFragmentContainer container = getSecondaryContainerForSplitIfAny(wct,
@@ -1567,6 +1621,12 @@
// background.
return;
}
+ final SplitContainer splitContainer = getActiveSplitForContainer(container);
+ if (splitContainer instanceof SplitPinContainer
+ && updateSplitContainerIfNeeded(splitContainer, wct, null /* splitAttributes */)) {
+ // A SplitPinContainer exists and is updated.
+ return;
+ }
if (launchPlaceholderIfNecessary(wct, container)) {
// Placeholder was launched, the positions will be updated when the activity is added
// to the secondary container.
@@ -1579,7 +1639,6 @@
// If the info is not available yet the task fragment will be expanded when it's ready
return;
}
- SplitContainer splitContainer = getActiveSplitForContainer(container);
if (splitContainer == null) {
return;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPinContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPinContainer.java
new file mode 100644
index 0000000..03c77a0
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPinContainer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.window.extensions.embedding;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Client-side descriptor of a split that holds two containers while the secondary
+ * container is pinned on top of the Task and the primary container is the container that is
+ * currently below the secondary container. The primary container could be updated to
+ * another container whenever the existing primary container is removed or no longer
+ * be the container that's right behind the secondary container.
+ */
+class SplitPinContainer extends SplitContainer {
+
+ SplitPinContainer(@NonNull TaskFragmentContainer primaryContainer,
+ @NonNull TaskFragmentContainer secondaryContainer,
+ @NonNull SplitPinRule splitPinRule,
+ @NonNull SplitAttributes splitAttributes) {
+ super(primaryContainer, primaryContainer.getTopNonFinishingActivity(), secondaryContainer,
+ splitPinRule, splitAttributes, true /* isPrimaryContainerMutable */);
+ }
+
+ @Override
+ public String toString() {
+ return "SplitPinContainer{"
+ + " primaryContainer=" + getPrimaryContainer()
+ + " secondaryContainer=" + getSecondaryContainer()
+ + " splitPinRule=" + getSplitRule()
+ + " splitAttributes" + getCurrentSplitAttributes()
+ + "}";
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 53d39d9..4dafbd1 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -17,6 +17,7 @@
package androidx.window.extensions.embedding;
import static android.content.pm.PackageManager.MATCH_ALL;
+import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
import android.app.Activity;
import android.app.ActivityThread;
@@ -39,6 +40,7 @@
import android.view.WindowMetrics;
import android.window.TaskFragmentAnimationParams;
import android.window.TaskFragmentCreationParams;
+import android.window.TaskFragmentOperation;
import android.window.WindowContainerTransaction;
import androidx.annotation.IntDef;
@@ -336,10 +338,6 @@
// value.
final SplitRule rule = splitContainer.getSplitRule();
final TaskFragmentContainer primaryContainer = splitContainer.getPrimaryContainer();
- final Activity activity = primaryContainer.getTopNonFinishingActivity();
- if (activity == null) {
- return;
- }
final TaskContainer taskContainer = splitContainer.getTaskContainer();
final TaskProperties taskProperties = taskContainer.getTaskProperties();
final SplitAttributes splitAttributes = splitContainer.getCurrentSplitAttributes();
@@ -424,6 +422,16 @@
container.setLastRequestedBounds(fragmentOptions.getInitialRelativeBounds());
container.setLastRequestedWindowingMode(fragmentOptions.getWindowingMode());
super.createTaskFragment(wct, fragmentOptions);
+
+ // Reorders the pinned TaskFragment to front to ensure it is the front-most TaskFragment.
+ final SplitPinContainer pinnedContainer =
+ container.getTaskContainer().getSplitPinContainer();
+ if (pinnedContainer != null) {
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REORDER_TO_FRONT).build();
+ wct.addTaskFragmentOperation(
+ pinnedContainer.getSecondaryContainer().getTaskFragmentToken(), operation);
+ }
}
@Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 4580c98..969e3ed 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -57,6 +57,10 @@
@NonNull
private final List<SplitContainer> mSplitContainers = new ArrayList<>();
+ /** Active pin split pair in this Task. */
+ @Nullable
+ private SplitPinContainer mSplitPinContainer;
+
@NonNull
private final Configuration mConfiguration;
@@ -174,11 +178,28 @@
}
@Nullable
- TaskFragmentContainer getTopTaskFragmentContainer() {
- if (mContainers.isEmpty()) {
- return null;
+ TaskFragmentContainer getTopNonFinishingTaskFragmentContainer() {
+ for (int i = mContainers.size() - 1; i >= 0; i--) {
+ final TaskFragmentContainer container = mContainers.get(i);
+ if (!container.isFinished()) {
+ return container;
+ }
}
- return mContainers.get(mContainers.size() - 1);
+ return null;
+ }
+
+ /** Gets a non-finishing container below the given one. */
+ @Nullable
+ TaskFragmentContainer getNonFinishingTaskFragmentContainerBelow(
+ @NonNull TaskFragmentContainer current) {
+ final int index = mContainers.indexOf(current);
+ for (int i = index - 1; i >= 0; i--) {
+ final TaskFragmentContainer container = mContainers.get(i);
+ if (!container.isFinished()) {
+ return container;
+ }
+ }
+ return null;
}
@Nullable
@@ -217,31 +238,57 @@
}
void addSplitContainer(@NonNull SplitContainer splitContainer) {
+ if (splitContainer instanceof SplitPinContainer) {
+ mSplitPinContainer = (SplitPinContainer) splitContainer;
+ mSplitContainers.add(splitContainer);
+ return;
+ }
+
+ // Keeps the SplitPinContainer on the top of the list.
+ mSplitContainers.remove(mSplitPinContainer);
mSplitContainers.add(splitContainer);
+ if (mSplitPinContainer != null) {
+ mSplitContainers.add(mSplitPinContainer);
+ }
}
void removeSplitContainers(@NonNull List<SplitContainer> containers) {
mSplitContainers.removeAll(containers);
}
+ void removeSplitPinContainer() {
+ mSplitContainers.remove(mSplitPinContainer);
+ mSplitPinContainer = null;
+ }
+
+ @Nullable
+ SplitPinContainer getSplitPinContainer() {
+ return mSplitPinContainer;
+ }
+
void addTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
mContainers.add(taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
}
void addTaskFragmentContainer(int index, @NonNull TaskFragmentContainer taskFragmentContainer) {
mContainers.add(index, taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
}
void removeTaskFragmentContainer(@NonNull TaskFragmentContainer taskFragmentContainer) {
mContainers.remove(taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
}
void removeTaskFragmentContainers(@NonNull List<TaskFragmentContainer> taskFragmentContainer) {
mContainers.removeAll(taskFragmentContainer);
+ onTaskFragmentContainerUpdated();
}
void clearTaskFragmentContainer() {
mContainers.clear();
+ onTaskFragmentContainerUpdated();
}
/**
@@ -254,6 +301,34 @@
return mContainers;
}
+ private void onTaskFragmentContainerUpdated() {
+ if (mSplitPinContainer == null) {
+ return;
+ }
+
+ final TaskFragmentContainer pinnedContainer = mSplitPinContainer.getSecondaryContainer();
+ final int pinnedContainerIndex = mContainers.indexOf(pinnedContainer);
+ if (pinnedContainerIndex <= 0) {
+ removeSplitPinContainer();
+ return;
+ }
+
+ // Ensure the pinned container is top-most.
+ if (pinnedContainerIndex != mContainers.size() - 1) {
+ mContainers.remove(pinnedContainer);
+ mContainers.add(pinnedContainer);
+ }
+
+ // Update the primary container adjacent to the pinned container if needed.
+ final TaskFragmentContainer adjacentContainer =
+ getNonFinishingTaskFragmentContainerBelow(pinnedContainer);
+ if (adjacentContainer == null) {
+ removeSplitPinContainer();
+ } else if (mSplitPinContainer.getPrimaryContainer() != adjacentContainer) {
+ mSplitPinContainer.setPrimaryContainer(adjacentContainer);
+ }
+ }
+
/** Adds the descriptors of split states in this Task to {@code outSplitStates}. */
void getSplitStates(@NonNull List<SplitInfo> outSplitStates) {
for (SplitContainer container : mSplitContainers) {
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 9e26472..9af1fe91 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -1462,6 +1462,51 @@
verify(testRecord).apply(eq(false));
}
+ @Test
+ public void testPinTopActivityStack() {
+ // Create two activities.
+ final Activity primaryActivity = createMockActivity();
+ final Activity secondaryActivity = createMockActivity();
+
+ // Unable to pin if not being embedded.
+ SplitPinRule splitPinRule = new SplitPinRule.Builder(new SplitAttributes.Builder().build(),
+ parentWindowMetrics -> true /* parentWindowMetricsPredicate */).build();
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Split the two activities.
+ addSplitTaskFragments(primaryActivity, secondaryActivity);
+ final TaskFragmentContainer primaryContainer =
+ mSplitController.getContainerWithActivity(primaryActivity);
+ spyOn(primaryContainer);
+
+ // Unable to pin if no valid TaskFragment.
+ doReturn(true).when(primaryContainer).isFinished();
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Otherwise, should pin successfully.
+ doReturn(false).when(primaryContainer).isFinished();
+ assertTrue(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Unable to pin if there is already a pinned TaskFragment
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID, splitPinRule));
+
+ // Unable to pin on an unknown Task.
+ assertFalse(mSplitController.pinTopActivityStack(TASK_ID + 1, splitPinRule));
+
+ // Gets the current size of all the SplitContainers.
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+ final int splitContainerCount = taskContainer.getSplitContainers().size();
+
+ // Create another activity and split with primary activity.
+ final Activity thirdActivity = createMockActivity();
+ addSplitTaskFragments(primaryActivity, thirdActivity);
+
+ // Ensure another SplitContainer is added and the pinned TaskFragment still on top
+ assertTrue(taskContainer.getSplitContainers().size() == splitContainerCount + +1);
+ assertTrue(mSplitController.getTopActiveContainer(TASK_ID).getTopNonFinishingActivity()
+ == secondaryActivity);
+ }
+
/** Creates a mock activity in the organizer process. */
private Activity createMockActivity() {
return createMockActivity(TASK_ID);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index 11af1d1..000c65a 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -135,15 +135,15 @@
@Test
public void testGetTopTaskFragmentContainer() {
final TaskContainer taskContainer = createTestTaskContainer();
- assertNull(taskContainer.getTopTaskFragmentContainer());
+ assertNull(taskContainer.getTopNonFinishingTaskFragmentContainer());
final TaskFragmentContainer tf0 = new TaskFragmentContainer(null /* activity */,
new Intent(), taskContainer, mController, null /* pairedPrimaryContainer */);
- assertEquals(tf0, taskContainer.getTopTaskFragmentContainer());
+ assertEquals(tf0, taskContainer.getTopNonFinishingTaskFragmentContainer());
final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
new Intent(), taskContainer, mController, null /* pairedPrimaryContainer */);
- assertEquals(tf1, taskContainer.getTopTaskFragmentContainer());
+ assertEquals(tf1, taskContainer.getTopNonFinishingTaskFragmentContainer());
}
@Test
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 3d4b55a..64fed1c 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -226,8 +226,6 @@
<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 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.. -->
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..8def8ff 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
@@ -1075,8 +1075,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 bubbleBarOffsetX,
+ int bubbleBarOffsetY) {
+ mBubblePositioner.setBubbleBarPosition(bubbleBarOffsetX, bubbleBarOffsetY);
if (BubbleOverflow.KEY.equals(key)) {
mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow());
@@ -2087,9 +2088,10 @@
}
@Override
- public void showBubble(String key, boolean onLauncherHome) {
+ public void showBubble(String key, int bubbleBarOffsetX, int bubbleBarOffsetY) {
mMainExecutor.execute(
- () -> mController.expandStackAndSelectBubbleFromLauncher(key, onLauncherHome));
+ () -> mController.expandStackAndSelectBubbleFromLauncher(
+ key, bubbleBarOffsetX, bubbleBarOffsetY));
}
@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..ee6996d 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()
@@ -723,10 +719,15 @@
}
/**
- * Sets whether bubbles are showing on launcher home, in which case positions are different.
+ * Sets the position of the bubble bar in screen coordinates.
+ *
+ * @param offsetX the offset of the bubble bar from the edge of the screen on the X axis
+ * @param offsetY the offset of the bubble bar from the edge of the screen on the Y axis
*/
- public void setBubblesOnHome(boolean bubblesOnHome) {
- mBubblesOnHome = bubblesOnHome;
+ public void setBubbleBarPosition(int offsetX, int offsetY) {
+ mBubbleBarPosition.set(
+ getAvailableRect().width() - offsetX,
+ getAvailableRect().height() + mInsets.top + mInsets.bottom - offsetY);
}
/**
@@ -747,11 +748,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 +761,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..351319f 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,7 @@
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 bubbleBarOffsetX, in int bubbleBarOffsetY) = 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 e97390d..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,7 +21,7 @@
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;
@@ -136,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,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
index 21355a3..24608d6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubbleInfo.java
@@ -129,6 +129,11 @@
return (mFlags & Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION) != 0;
}
+ /** Sets the flags for this bubble. */
+ public void setFlags(int flags) {
+ mFlags = flags;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
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/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b14c3c1..08da485 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1927,6 +1927,7 @@
pw.println(innerPrefix + "mLeash=" + mLeash);
pw.println(innerPrefix + "mState=" + mPipTransitionState.getTransitionState());
pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
+ mPipTransitionController.dump(pw, innerPrefix);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 73eb62a..e3d53fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -72,6 +72,7 @@
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.TransitionUtil;
+import java.io.PrintWriter;
import java.util.Optional;
/**
@@ -451,6 +452,9 @@
@Override
public void forceFinishTransition() {
+ // mFinishCallback might be null with an outdated mCurrentPipTaskToken
+ // for example, when app crashes while in PiP and exit transition has not started
+ mCurrentPipTaskToken = null;
if (mFinishCallback == null) return;
mFinishCallback.onTransitionFinished(null /* wct */, null /* callback */);
mFinishCallback = null;
@@ -1137,4 +1141,12 @@
PipMenuController.ALPHA_NO_CHANGE);
mPipMenuController.updateMenuBounds(destinationBounds);
}
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mCurrentPipTaskToken=" + mCurrentPipTaskToken);
+ pw.println(innerPrefix + "mFinishCallback=" + mFinishCallback);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index e1bcd70c..6362793 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -42,6 +42,7 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -283,4 +284,9 @@
*/
void onPipTransitionCanceled(int direction);
}
+
+ /**
+ * Dumps internal states.
+ */
+ public void dump(PrintWriter pw, String prefix) {}
}
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/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 693bf6c..7d62f58 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
@@ -740,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) {
@@ -2564,6 +2564,9 @@
// so don't handle it.
Log.e(TAG, "Somehow removed the last task in a stage outside of a proper "
+ "transition.");
+ // This new transition would be merged to current one so we need to clear
+ // tile manually here.
+ clearSplitPairedInRecents(EXIT_REASON_APP_FINISHED);
final WindowContainerTransaction wct = new WindowContainerTransaction();
final int dismissTop = (dismissStages.size() == 1
&& getStageType(dismissStages.valueAt(0)) == STAGE_TYPE_MAIN)
@@ -2588,8 +2591,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;
}
}
@@ -2744,6 +2750,12 @@
Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
"launched 2 tasks in split, but didn't receive "
+ "2 tasks in transition. Possibly one of them failed to launch"));
+ if (mRecentTasks.isPresent() && mainChild != null) {
+ mRecentTasks.get().removeSplitPair(mainChild.getTaskInfo().taskId);
+ }
+ if (mRecentTasks.isPresent() && sideChild != null) {
+ mRecentTasks.get().removeSplitPair(sideChild.getTaskInfo().taskId);
+ }
mSplitUnsupportedToast.show();
return true;
}
@@ -2959,8 +2971,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/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
index 5f54f58..56c0d0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
@@ -38,8 +38,6 @@
public static final String KEY_EXTRA_SHELL_RECENT_TASKS = "extra_shell_recent_tasks";
// See IBackAnimation.aidl
public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation";
- // See IFloatingTasks.aidl
- public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks";
// See IDesktopMode.aidl
public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode";
// See IDragAndDrop.aidl
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 14f2f9b..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
@@ -799,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/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/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt
index 96bfb78..d1dd8df 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.kt
@@ -23,6 +23,7 @@
import android.util.Log
import com.android.dream.lowlight.dagger.LowLightDreamModule
import com.android.dream.lowlight.dagger.qualifiers.Application
+import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.TimeoutCancellationException
@@ -103,6 +104,11 @@
)
} catch (ex: TimeoutCancellationException) {
Log.e(TAG, "timed out while waiting for low light animation", ex)
+ } catch (ex: CancellationException) {
+ Log.w(TAG, "low light transition animation cancelled")
+ // Catch the cancellation so that we still set the system dream component if the
+ // animation is cancelled, such as by a user tapping to wake as the transition to
+ // low light happens.
}
dreamManager.setSystemDreamComponent(
if (shouldEnterLowLight) lowLightDreamComponent else null
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..de1aee5 100644
--- a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightTransitionCoordinator.kt
@@ -110,9 +110,5 @@
}
}
animator.addListener(listener)
- continuation.invokeOnCancellation {
- animator.removeListener(listener)
- animator.cancel()
- }
}
}
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/util/TruncatedInterpolator.kt b/libs/dream/lowlight/src/com/android/dream/lowlight/util/TruncatedInterpolator.kt
new file mode 100644
index 0000000..f69c84d
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/util/TruncatedInterpolator.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dream.lowlight.util
+
+import android.view.animation.Interpolator
+
+/**
+ * Interpolator wrapper that shortens another interpolator from its original duration to a portion
+ * of that duration.
+ *
+ * For example, an `originalDuration` of 1000 and a `newDuration` of 200 results in an animation
+ * that when played for 200ms is the exact same as the first 200ms of a 1000ms animation if using
+ * the original interpolator.
+ *
+ * This is useful for the transition between the user dream and the low light clock as some
+ * animations are defined in the spec to be longer than the total duration of the animation. For
+ * example, the low light clock exit translation animation is defined to last >1s while the actual
+ * fade out of the low light clock is only 250ms, meaning the clock isn't visible anymore after
+ * 250ms.
+ *
+ * Since the dream framework currently only allows one dream to be visible and running, we use this
+ * interpolator to play just the first 250ms of the translation animation. Simply reducing the
+ * duration of the animation would result in the text exiting much faster than intended, so a custom
+ * interpolator is needed.
+ */
+class TruncatedInterpolator(
+ private val baseInterpolator: Interpolator,
+ originalDuration: Float,
+ newDuration: Float
+) : Interpolator {
+ private val scaleFactor: Float
+
+ init {
+ scaleFactor = newDuration / originalDuration
+ }
+
+ override fun getInterpolation(input: Float): Float {
+ return baseInterpolator.getInterpolation(input * scaleFactor)
+ }
+}
diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp
index 2d79090..64b53cb 100644
--- a/libs/dream/lowlight/tests/Android.bp
+++ b/libs/dream/lowlight/tests/Android.bp
@@ -27,6 +27,7 @@
"androidx.test.runner",
"androidx.test.rules",
"androidx.test.ext.junit",
+ "animationlib",
"frameworks-base-testutils",
"junit",
"kotlinx_coroutines_test",
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt
index 2a886bc..de84adb 100644
--- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.kt
@@ -152,6 +152,21 @@
verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
}
+ @Test
+ fun setAmbientLightMode_animationCancelled_SetsSystemDream() = testScope.runTest {
+ mLowLightDreamManager.setAmbientLightMode(LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT)
+ runCurrent()
+ cancelEnterAnimations()
+ runCurrent()
+ // Animation never finishes, but we should still set the system dream
+ verify(mDreamManager).setSystemDreamComponent(DREAM_COMPONENT)
+ }
+
+ private fun cancelEnterAnimations() {
+ val listener = withArgCaptor { verify(mEnterAnimator).addListener(capture()) }
+ listener.onAnimationCancel(mEnterAnimator)
+ }
+
private fun completeEnterAnimations() {
val listener = withArgCaptor { verify(mEnterAnimator).addListener(capture()) }
listener.onAnimationEnd(mEnterAnimator)
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt
index 4c526a6..9ae304f 100644
--- a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightTransitionCoordinatorTest.kt
@@ -158,26 +158,6 @@
assertThat(job.isCancelled).isTrue()
}
- @Test
- fun shouldCancelAnimatorWhenJobCancelled() = testScope.runTest {
- whenever(mEnterListener.onBeforeEnterLowLight()).thenReturn(mAnimator)
- val coordinator = LowLightTransitionCoordinator()
- coordinator.setLowLightEnterListener(mEnterListener)
- val job = launch {
- coordinator.waitForLowLightTransitionAnimation(timeout = TIMEOUT, entering = true)
- }
- runCurrent()
- // Animator listener is added and the runnable is not run yet.
- verify(mAnimator).addListener(mAnimatorListenerCaptor.capture())
- verify(mAnimator, never()).cancel()
- assertThat(job.isCompleted).isFalse()
-
- job.cancel()
- // We should have removed the listener and cancelled the animator
- verify(mAnimator).removeListener(mAnimatorListenerCaptor.value)
- verify(mAnimator).cancel()
- }
-
companion object {
private val TIMEOUT = 1.toDuration(DurationUnit.SECONDS)
}
diff --git a/libs/dream/lowlight/tests/src/com/android/dream/lowlight/util/TruncatedInterpolatorTest.kt b/libs/dream/lowlight/tests/src/com/android/dream/lowlight/util/TruncatedInterpolatorTest.kt
new file mode 100644
index 0000000..190f02e
--- /dev/null
+++ b/libs/dream/lowlight/tests/src/com/android/dream/lowlight/util/TruncatedInterpolatorTest.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.dream.lowlight.util
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class TruncatedInterpolatorTest {
+ @Test
+ fun truncatedInterpolator_matchesRegularInterpolator() {
+ val originalInterpolator = Interpolators.EMPHASIZED
+ val truncatedInterpolator =
+ TruncatedInterpolator(originalInterpolator, ORIGINAL_DURATION_MS, NEW_DURATION_MS)
+
+ // Both interpolators should start at the same value.
+ var animationPercent = 0f
+ Truth.assertThat(truncatedInterpolator.getInterpolation(animationPercent))
+ .isEqualTo(originalInterpolator.getInterpolation(animationPercent))
+
+ animationPercent = 1f
+ Truth.assertThat(truncatedInterpolator.getInterpolation(animationPercent))
+ .isEqualTo(originalInterpolator.getInterpolation(animationPercent * DURATION_RATIO))
+
+ animationPercent = 0.25f
+ Truth.assertThat(truncatedInterpolator.getInterpolation(animationPercent))
+ .isEqualTo(originalInterpolator.getInterpolation(animationPercent * DURATION_RATIO))
+ }
+
+ companion object {
+ private const val ORIGINAL_DURATION_MS: Float = 1000f
+ private const val NEW_DURATION_MS: Float = 200f
+ private const val DURATION_RATIO: Float = NEW_DURATION_MS / ORIGINAL_DURATION_MS
+ }
+}
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/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/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/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/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/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 01e6bf0..bb8002a 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -53,6 +53,20 @@
]
},
{
+ "name": "SystemUIGoogleScreenshotTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.Postsubmit"
+ }
+ ]
+ },
+ {
// TODO(b/251476085): Consider merging with SystemUIGoogleScreenshotTests (in U+)
"name": "SystemUIGoogleBiometricsScreenshotTests",
"options": [
@@ -131,5 +145,21 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "SystemUIGoogleScreenshotTests",
+ "options": [
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Postsubmit"
+ }
+ ]
+ }
]
}
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/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%
rename from core/res/res/color/letterbox_background.xml
rename 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/activity_rear_display_education.xml b/packages/SystemUI/res/layout/activity_rear_display_education.xml
index c295cfe..1b6247f 100644
--- a/packages/SystemUI/res/layout/activity_rear_display_education.xml
+++ b/packages/SystemUI/res/layout/activity_rear_display_education.xml
@@ -28,7 +28,7 @@
app:cardCornerRadius="28dp"
app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.reardisplay.RearDisplayEducationLottieViewWrapper
android:id="@+id/rear_display_folded_animation"
android:importantForAccessibility="no"
android:layout_width="@dimen/rear_display_animation_width"
diff --git a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
index 0e6b281..bded012 100644
--- a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
+++ b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
@@ -29,7 +29,7 @@
app:cardCornerRadius="28dp"
app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.reardisplay.RearDisplayEducationLottieViewWrapper
android:id="@+id/rear_display_folded_animation"
android:importantForAccessibility="no"
android:layout_width="@dimen/rear_display_animation_width_opened"
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index efc661a..50b3bec 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -57,7 +57,7 @@
<include layout="@layout/auth_biometric_icon"/>
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
android:id="@+id/biometric_icon_overlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/biometric_prompt_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_layout.xml
index 05ff1b1..ecb0bfa 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
@@ -59,7 +60,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center">
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
android:id="@+id/biometric_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -67,7 +68,7 @@
android:contentDescription="@null"
android:scaleType="fitXY" />
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
android:id="@+id/biometric_icon_overlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
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/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/sidefps_view.xml b/packages/SystemUI/res/layout/sidefps_view.xml
index 73050c2..4d95220 100644
--- a/packages/SystemUI/res/layout/sidefps_view.xml
+++ b/packages/SystemUI/res/layout/sidefps_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.airbnb.lottie.LottieAnimationView
+<com.android.systemui.biometrics.SideFpsLottieViewWrapper
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sidefps_animation"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 331307a0..0ab921f 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.xml b/packages/SystemUI/res/layout/status_bar_wifi_group.xml
deleted file mode 100644
index 6cb6993b..0000000
--- a/packages/SystemUI/res/layout/status_bar_wifi_group.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2018, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<com.android.systemui.statusbar.StatusBarWifiView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/wifi_combo"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical" >
-
- <include layout="@layout/status_bar_wifi_group_inner" />
-
-</com.android.systemui.statusbar.StatusBarWifiView>
\ No newline at end of file
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/layout/udfps_keyguard_preview.xml b/packages/SystemUI/res/layout/udfps_keyguard_preview.xml
index c068b7b..0964a21 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_preview.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_preview.xml
@@ -24,7 +24,7 @@
android:background="@drawable/fingerprint_bg">
<!-- LockScreen fingerprint icon from 0 stroke width to full width -->
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.keyguard.ui.view.UdfpsLottieViewWrapper
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml b/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
index 191158e..1d6147c 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view_internal.xml
@@ -32,7 +32,7 @@
<!-- Fingerprint -->
<!-- AOD dashed fingerprint icon with moving dashes -->
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.keyguard.ui.view.UdfpsLottieViewWrapper
android:id="@+id/udfps_aod_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -43,7 +43,7 @@
app:lottie_rawRes="@raw/udfps_aod_fp"/>
<!-- LockScreen fingerprint icon from 0 stroke width to full width -->
- <com.airbnb.lottie.LottieAnimationView
+ <com.android.systemui.keyguard.ui.view.UdfpsLottieViewWrapper
android:id="@+id/udfps_lockscreen_fp"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml
index ab52465..3baae33 100644
--- a/packages/SystemUI/res/layout/zen_mode_condition.xml
+++ b/packages/SystemUI/res/layout/zen_mode_condition.xml
@@ -15,6 +15,7 @@
limitations under the License.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:theme="@style/Theme.SystemUI.QuickSettings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
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 d9466bf..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 -->
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..f8c13b0 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] -->
@@ -1107,6 +1114,16 @@
<!-- System sharing media projection permission button to continue. [CHAR LIMIT=60] -->
<string name="media_projection_entry_generic_permission_dialog_continue">Start</string>
+ <!-- Task switcher notification -->
+ <!-- Task switcher notification text. [CHAR LIMIT=100] -->
+ <string name="media_projection_task_switcher_text">Sharing pauses when you switch apps</string>
+ <!-- The action for switching to the foreground task. [CHAR LIMIT=40] -->
+ <string name="media_projection_task_switcher_action_switch">Share this app instead</string>
+ <!-- The action for switching back to the projected task. [CHAR LIMIT=40] -->
+ <string name="media_projection_task_switcher_action_back">Switch back</string>
+ <!-- Task switcher notification channel name. [CHAR LIMIT=40] -->
+ <string name="media_projection_task_switcher_notification_channel">App switch</string>
+
<!-- Title for the dialog that is shown when screen capturing is disabled by enterprise policy. [CHAR LIMIT=100] -->
<string name="screen_capturing_disabled_by_policy_dialog_title">Blocked by your IT admin</string>
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/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
index 0fbeb1a..f3296f0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
@@ -32,7 +32,7 @@
@JvmOverloads
constructor(
val sampledView: View,
- mainExecutor: Executor?,
+ val mainExecutor: Executor?,
val bgExecutor: Executor?,
val regionSamplingEnabled: Boolean,
val isLockscreen: Boolean = false,
@@ -166,7 +166,7 @@
if (isLockscreen) WallpaperManager.FLAG_LOCK
else WallpaperManager.FLAG_SYSTEM
)
- onColorsChanged(sampledRegionWithOffset, initialSampling)
+ mainExecutor?.execute { onColorsChanged(sampledRegionWithOffset, initialSampling) }
}
)
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index ca064ef..4b14d3cf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -42,8 +42,6 @@
"com.google.android.apps.nexuslauncher.NexusLauncherActivity";
public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
- public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
- public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
public static final String KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER = "extra_unfold_animation";
// See ISysuiUnlockAnimationController.aidl
public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation";
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
deleted file mode 100644
index 74c325d..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ /dev/null
@@ -1,541 +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.systemui.shared.system;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_LOCKED;
-import static android.view.WindowManager.TRANSIT_SLEEP;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.IApplicationThread;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.view.IRecentsAnimationController;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.window.IRemoteTransition;
-import android.window.IRemoteTransitionFinishedCallback;
-import android.window.PictureInPictureSurfaceTransaction;
-import android.window.RemoteTransition;
-import android.window.TaskSnapshot;
-import android.window.TransitionInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.wm.shell.util.TransitionUtil;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * Helper class to build {@link RemoteTransition} objects
- */
-public class RemoteTransitionCompat {
- private static final String TAG = "RemoteTransitionCompat";
-
- /** Constructor specifically for recents animation */
- public static RemoteTransition newRemoteTransition(RecentsAnimationListener recents,
- IApplicationThread appThread) {
- IRemoteTransition remote = new IRemoteTransition.Stub() {
- final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap();
- IBinder mToken = null;
-
- @Override
- public void startAnimation(IBinder transition, TransitionInfo info,
- SurfaceControl.Transaction t,
- IRemoteTransitionFinishedCallback finishedCallback) {
- // TODO(b/177438007): Move this set-up logic into launcher's animation impl.
- mToken = transition;
- mRecentsSession.start(recents, mToken, info, t, finishedCallback);
- }
-
- @Override
- public void mergeAnimation(IBinder transition, TransitionInfo info,
- SurfaceControl.Transaction t, IBinder mergeTarget,
- IRemoteTransitionFinishedCallback finishedCallback) {
- if (mergeTarget.equals(mToken) && mRecentsSession.merge(info, t)) {
- try {
- finishedCallback.onTransitionFinished(null /* wct */, null /* sct */);
- } catch (RemoteException e) {
- Log.e(TAG, "Error merging transition.", e);
- }
- // commit taskAppeared after merge transition finished.
- mRecentsSession.commitTasksAppearedIfNeeded();
- } else {
- t.close();
- info.releaseAllSurfaces();
- }
- }
- };
- return new RemoteTransition(remote, appThread, "Recents");
- }
-
- /**
- * Wrapper to hook up parts of recents animation to shell transition.
- * TODO(b/177438007): Remove this once Launcher handles shell transitions directly.
- */
- @VisibleForTesting
- static class RecentsControllerWrap extends IRecentsAnimationController.Default {
- private RecentsAnimationListener mListener = null;
- private IRemoteTransitionFinishedCallback mFinishCB = null;
-
- /**
- * List of tasks that we are switching away from via this transition. Upon finish, these
- * pausing tasks will become invisible.
- * These need to be ordered since the order must be restored if there is no task-switch.
- */
- private ArrayList<TaskState> mPausingTasks = null;
-
- /**
- * List of tasks that we are switching to. Upon finish, these will remain visible and
- * on top.
- */
- private ArrayList<TaskState> mOpeningTasks = null;
-
- private WindowContainerToken mPipTask = null;
- private WindowContainerToken mRecentsTask = null;
- private int mRecentsTaskId = 0;
- private TransitionInfo mInfo = null;
- private boolean mOpeningSeparateHome = false;
- private ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = null;
- private PictureInPictureSurfaceTransaction mPipTransaction = null;
- private IBinder mTransition = null;
- private boolean mKeyguardLocked = false;
- private RemoteAnimationTarget[] mAppearedTargets;
- private boolean mWillFinishToHome = false;
-
- /** The animation is idle, waiting for the user to choose a task to switch to. */
- private static final int STATE_NORMAL = 0;
-
- /** The user chose a new task to switch to and the animation is animating to it. */
- private static final int STATE_NEW_TASK = 1;
-
- /** The latest state that the recents animation is operating in. */
- private int mState = STATE_NORMAL;
-
- void start(RecentsAnimationListener listener,
- IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
- IRemoteTransitionFinishedCallback finishedCallback) {
- if (mInfo != null) {
- throw new IllegalStateException("Trying to run a new recents animation while"
- + " recents is already active.");
- }
- mListener = listener;
- mInfo = info;
- mFinishCB = finishedCallback;
- mPausingTasks = new ArrayList<>();
- mOpeningTasks = new ArrayList<>();
- mPipTask = null;
- mRecentsTask = null;
- mRecentsTaskId = -1;
- mLeashMap = new ArrayMap<>();
- mTransition = transition;
- mKeyguardLocked = (info.getFlags() & TRANSIT_FLAG_KEYGUARD_LOCKED) != 0;
- mState = STATE_NORMAL;
-
- final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
- final ArrayList<RemoteAnimationTarget> wallpapers = new ArrayList<>();
- TransitionUtil.LeafTaskFilter leafTaskFilter = new TransitionUtil.LeafTaskFilter();
- // About layering: we divide up the "layer space" into 3 regions (each the size of
- // the change count). This lets us categorize things into above/below/between
- // while maintaining their relative ordering.
- for (int i = 0; i < info.getChanges().size(); ++i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- if (TransitionUtil.isWallpaper(change)) {
- final RemoteAnimationTarget target = TransitionUtil.newTarget(change,
- // wallpapers go into the "below" layer space
- info.getChanges().size() - i, info, t, mLeashMap);
- wallpapers.add(target);
- // Make all the wallpapers opaque since we want them visible from the start
- t.setAlpha(target.leash, 1);
- } else if (leafTaskFilter.test(change)) {
- // start by putting everything into the "below" layer space.
- final RemoteAnimationTarget target = TransitionUtil.newTarget(change,
- info.getChanges().size() - i, info, t, mLeashMap);
- apps.add(target);
- if (TransitionUtil.isClosingType(change.getMode())) {
- // raise closing (pausing) task to "above" layer so it isn't covered
- t.setLayer(target.leash, info.getChanges().size() * 3 - i);
- mPausingTasks.add(new TaskState(change, target.leash));
- if (taskInfo.pictureInPictureParams != null
- && taskInfo.pictureInPictureParams.isAutoEnterEnabled()) {
- mPipTask = taskInfo.token;
- }
- } else if (taskInfo != null
- && taskInfo.topActivityType == ACTIVITY_TYPE_RECENTS) {
- // There's a 3p launcher, so make sure recents goes above that.
- t.setLayer(target.leash, info.getChanges().size() * 3 - i);
- mRecentsTask = taskInfo.token;
- mRecentsTaskId = taskInfo.taskId;
- } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
- mRecentsTask = taskInfo.token;
- mRecentsTaskId = taskInfo.taskId;
- } else if (TransitionUtil.isOpeningType(change.getMode())) {
- mOpeningTasks.add(new TaskState(change, target.leash));
- }
- }
- }
- t.apply();
- mListener.onAnimationStart(new RecentsAnimationControllerCompat(this),
- apps.toArray(new RemoteAnimationTarget[apps.size()]),
- wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]),
- new Rect(0, 0, 0, 0), new Rect());
- }
-
- @SuppressLint("NewApi")
- boolean merge(TransitionInfo info, SurfaceControl.Transaction t) {
- if (info.getType() == TRANSIT_SLEEP) {
- // A sleep event means we need to stop animations immediately, so cancel here.
- mListener.onAnimationCanceled(new HashMap<>());
- finish(mWillFinishToHome, false /* userLeaveHint */);
- return false;
- }
- ArrayList<TransitionInfo.Change> openingTasks = null;
- ArrayList<TransitionInfo.Change> closingTasks = null;
- mAppearedTargets = null;
- mOpeningSeparateHome = false;
- TransitionInfo.Change recentsOpening = null;
- boolean foundRecentsClosing = false;
- boolean hasChangingApp = false;
- final TransitionUtil.LeafTaskFilter leafTaskFilter =
- new TransitionUtil.LeafTaskFilter();
- for (int i = 0; i < info.getChanges().size(); ++i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
- final boolean isLeafTask = leafTaskFilter.test(change);
- if (TransitionUtil.isOpeningType(change.getMode())) {
- if (mRecentsTask.equals(change.getContainer())) {
- recentsOpening = change;
- } else if (isLeafTask) {
- if (taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
- // This is usually a 3p launcher
- mOpeningSeparateHome = true;
- }
- if (openingTasks == null) {
- openingTasks = new ArrayList<>();
- }
- openingTasks.add(change);
- }
- } else if (TransitionUtil.isClosingType(change.getMode())) {
- if (mRecentsTask.equals(change.getContainer())) {
- foundRecentsClosing = true;
- } else if (isLeafTask) {
- if (closingTasks == null) {
- closingTasks = new ArrayList<>();
- }
- closingTasks.add(change);
- }
- } else if (change.getMode() == TRANSIT_CHANGE) {
- // Finish recents animation if the display is changed, so the default
- // transition handler can play the animation such as rotation effect.
- if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) {
- mListener.onSwitchToScreenshot(() -> finish(false /* toHome */,
- false /* userLeaveHint */));
- return false;
- }
- hasChangingApp = true;
- }
- }
- if (hasChangingApp && foundRecentsClosing) {
- // This happens when a visible app is expanding (usually PiP). In this case,
- // that transition probably has a special-purpose animation, so finish recents
- // now and let it do its animation (since recents is going to be occluded).
- if (!mListener.onSwitchToScreenshot(
- () -> finish(true /* toHome */, false /* userLeaveHint */))) {
- Log.w(TAG, "Recents callback doesn't support support switching to screenshot"
- + ", there might be a flicker.");
- finish(true /* toHome */, false /* userLeaveHint */);
- }
- return false;
- }
- if (recentsOpening != null) {
- // the recents task re-appeared. This happens if the user gestures before the
- // task-switch (NEW_TASK) animation finishes.
- if (mState == STATE_NORMAL) {
- Log.e(TAG, "Returning to recents while recents is already idle.");
- }
- if (closingTasks == null || closingTasks.size() == 0) {
- Log.e(TAG, "Returning to recents without closing any opening tasks.");
- }
- // Setup may hide it initially since it doesn't know that overview was still active.
- t.show(recentsOpening.getLeash());
- t.setAlpha(recentsOpening.getLeash(), 1.f);
- mState = STATE_NORMAL;
- }
- boolean didMergeThings = false;
- if (closingTasks != null) {
- // Cancelling a task-switch. Move the tasks back to mPausing from mOpening
- for (int i = 0; i < closingTasks.size(); ++i) {
- final TransitionInfo.Change change = closingTasks.get(i);
- int openingIdx = TaskState.indexOf(mOpeningTasks, change);
- if (openingIdx < 0) {
- Log.e(TAG, "Back to existing recents animation from an unrecognized "
- + "task: " + change.getTaskInfo().taskId);
- continue;
- }
- mPausingTasks.add(mOpeningTasks.remove(openingIdx));
- didMergeThings = true;
- }
- }
- if (openingTasks != null && openingTasks.size() > 0) {
- // Switching to some new tasks, add to mOpening and remove from mPausing. Also,
- // enter NEW_TASK state since this will start the switch-to animation.
- final int layer = mInfo.getChanges().size() * 3;
- final RemoteAnimationTarget[] targets =
- new RemoteAnimationTarget[openingTasks.size()];
- for (int i = 0; i < openingTasks.size(); ++i) {
- final TransitionInfo.Change change = openingTasks.get(i);
- int pausingIdx = TaskState.indexOf(mPausingTasks, change);
- if (pausingIdx >= 0) {
- // Something is showing/opening a previously-pausing app.
- targets[i] = TransitionUtil.newTarget(change, layer,
- mPausingTasks.get(pausingIdx).mLeash);
- mOpeningTasks.add(mPausingTasks.remove(pausingIdx));
- // Setup hides opening tasks initially, so make it visible again (since we
- // are already showing it).
- t.show(change.getLeash());
- t.setAlpha(change.getLeash(), 1.f);
- } else {
- // We are receiving new opening tasks, so convert to onTasksAppeared.
- targets[i] = TransitionUtil.newTarget(change, layer, info, t, mLeashMap);
- // reparent into the original `mInfo` since that's where we are animating.
- final int rootIdx = TransitionUtil.rootIndexFor(change, mInfo);
- t.reparent(targets[i].leash, mInfo.getRoot(rootIdx).getLeash());
- t.setLayer(targets[i].leash, layer);
- mOpeningTasks.add(new TaskState(change, targets[i].leash));
- }
- }
- didMergeThings = true;
- mState = STATE_NEW_TASK;
- mAppearedTargets = targets;
- }
- if (!didMergeThings) {
- // Didn't recognize anything in incoming transition so don't merge it.
- Log.w(TAG, "Don't know how to merge this transition.");
- return false;
- }
- t.apply();
- // not using the incoming anim-only surfaces
- info.releaseAnimSurfaces();
- return true;
- }
-
- private void commitTasksAppearedIfNeeded() {
- if (mAppearedTargets != null) {
- mListener.onTasksAppeared(mAppearedTargets);
- mAppearedTargets = null;
- }
- }
-
- @Override public TaskSnapshot screenshotTask(int taskId) {
- try {
- return ActivityTaskManager.getService().takeTaskSnapshot(taskId,
- true /* updateCache */);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to screenshot task", e);
- }
- return null;
- }
-
- @Override public void setInputConsumerEnabled(boolean enabled) {
- if (!enabled) return;
- // transient launches don't receive focus automatically. Since we are taking over
- // the gesture now, take focus explicitly.
- // This also moves recents back to top if the user gestured before a switch
- // animation finished.
- try {
- ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to set focused task", e);
- }
- }
-
- @Override public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) {
- }
-
- @Override public void setFinishTaskTransaction(int taskId,
- PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
- mPipTransaction = finishTransaction;
- }
-
- @Override
- @SuppressLint("NewApi")
- public void finish(boolean toHome, boolean sendUserLeaveHint) {
- if (mFinishCB == null) {
- Log.e(TAG, "Duplicate call to finish", new RuntimeException());
- return;
- }
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
- if (mKeyguardLocked && mRecentsTask != null) {
- if (toHome) wct.reorder(mRecentsTask, true /* toTop */);
- else wct.restoreTransientOrder(mRecentsTask);
- }
- if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) {
- // The gesture is returning to the pausing-task(s) rather than continuing with
- // recents, so end the transition by moving the app back to the top (and also
- // re-showing it's task).
- for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
- // reverse order so that index 0 ends up on top
- wct.reorder(mPausingTasks.get(i).mToken, true /* onTop */);
- t.show(mPausingTasks.get(i).mTaskSurface);
- }
- if (!mKeyguardLocked && mRecentsTask != null) {
- wct.restoreTransientOrder(mRecentsTask);
- }
- } else if (toHome && mOpeningSeparateHome && mPausingTasks != null) {
- // Special situation where 3p launcher was changed during recents (this happens
- // during tapltests...). Here we get both "return to home" AND "home opening".
- // This is basically going home, but we have to restore the recents and home order.
- for (int i = 0; i < mOpeningTasks.size(); ++i) {
- final TaskState state = mOpeningTasks.get(i);
- if (state.mTaskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
- // Make sure it is on top.
- wct.reorder(state.mToken, true /* onTop */);
- }
- t.show(state.mTaskSurface);
- }
- for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
- t.hide(mPausingTasks.get(i).mTaskSurface);
- }
- if (!mKeyguardLocked && mRecentsTask != null) {
- wct.restoreTransientOrder(mRecentsTask);
- }
- } else {
- // The general case: committing to recents, going home, or switching tasks.
- for (int i = 0; i < mOpeningTasks.size(); ++i) {
- t.show(mOpeningTasks.get(i).mTaskSurface);
- }
- for (int i = 0; i < mPausingTasks.size(); ++i) {
- if (!sendUserLeaveHint) {
- // This means recents is not *actually* finishing, so of course we gotta
- // do special stuff in WMCore to accommodate.
- wct.setDoNotPip(mPausingTasks.get(i).mToken);
- }
- // Since we will reparent out of the leashes, pre-emptively hide the child
- // surface to match the leash. Otherwise, there will be a flicker before the
- // visibility gets committed in Core when using split-screen (in splitscreen,
- // the leaf-tasks are not "independent" so aren't hidden by normal setup).
- t.hide(mPausingTasks.get(i).mTaskSurface);
- }
- if (mPipTask != null && mPipTransaction != null && sendUserLeaveHint) {
- t.show(mInfo.getChange(mPipTask).getLeash());
- PictureInPictureSurfaceTransaction.apply(mPipTransaction,
- mInfo.getChange(mPipTask).getLeash(), t);
- mPipTask = null;
- mPipTransaction = null;
- }
- }
- try {
- mFinishCB.onTransitionFinished(wct.isEmpty() ? null : wct, t);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to call animation finish callback", e);
- t.apply();
- }
- // Only release the non-local created surface references. The animator is responsible
- // for releasing the leashes created by local.
- mInfo.releaseAllSurfaces();
- // Reset all members.
- mListener = null;
- mFinishCB = null;
- mPausingTasks = null;
- mOpeningTasks = null;
- mAppearedTargets = null;
- mInfo = null;
- mOpeningSeparateHome = false;
- mLeashMap = null;
- mTransition = null;
- mState = STATE_NORMAL;
- }
-
- @Override public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
- }
-
- @Override public void cleanupScreenshot() {
- }
-
- @Override public void setWillFinishToHome(boolean willFinishToHome) {
- mWillFinishToHome = willFinishToHome;
- }
-
- /**
- * @see IRecentsAnimationController#removeTask
- */
- @Override public boolean removeTask(int taskId) {
- return false;
- }
-
- /**
- * @see IRecentsAnimationController#detachNavigationBarFromApp
- */
- @Override public void detachNavigationBarFromApp(boolean moveHomeToTop) {
- try {
- ActivityTaskManager.getService().detachNavigationBarFromApp(mTransition);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to detach the navigation bar from app", e);
- }
- }
-
- /**
- * @see IRecentsAnimationController#animateNavigationBarToApp(long)
- */
- @Override public void animateNavigationBarToApp(long duration) {
- }
- }
-
- /** Utility class to track the state of a task as-seen by recents. */
- private static class TaskState {
- WindowContainerToken mToken;
- ActivityManager.RunningTaskInfo mTaskInfo;
-
- /** The surface/leash of the task provided by Core. */
- SurfaceControl mTaskSurface;
-
- /** The (local) animation-leash created for this task. */
- SurfaceControl mLeash;
-
- TaskState(TransitionInfo.Change change, SurfaceControl leash) {
- mToken = change.getContainer();
- mTaskInfo = change.getTaskInfo();
- mTaskSurface = change.getLeash();
- mLeash = leash;
- }
-
- static int indexOf(ArrayList<TaskState> list, TransitionInfo.Change change) {
- for (int i = list.size() - 1; i >= 0; --i) {
- if (list.get(i).mToken.equals(change.getContainer())) {
- return i;
- }
- }
- return -1;
- }
-
- public String toString() {
- return "" + mToken + " : " + mLeash;
- }
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
deleted file mode 100644
index 98212e1..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/FrameProtoTracer.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.shared.tracing;
-
-import android.os.Trace;
-import android.util.Log;
-import android.view.Choreographer;
-
-import com.android.internal.util.TraceBuffer;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Queue;
-import java.util.function.Consumer;
-
-/**
- * A proto tracer implementation that can be updated directly (upon state change), or on the next
- * scheduled frame.
- *
- * @param <P> The class type of the proto provider
- * @param <S> The proto class type of the encapsulating proto
- * @param <T> The proto class type of the individual proto entries in the buffer
- * @param <R> The proto class type of the entry root proto in the buffer
- */
-public class FrameProtoTracer<P, S extends P, T extends P, R>
- implements Choreographer.FrameCallback {
-
- private static final String TAG = "FrameProtoTracer";
- private static final int BUFFER_CAPACITY = 1024 * 1024;
-
- private final Object mLock = new Object();
- private final TraceBuffer<P, S, T> mBuffer;
- private final File mTraceFile;
- private final ProtoTraceParams<P, S, T, R> mParams;
- private Choreographer mChoreographer;
- private final Queue<T> mPool = new ArrayDeque<>();
- private final ArrayList<ProtoTraceable<R>> mTraceables = new ArrayList<>();
- private final ArrayList<ProtoTraceable<R>> mTmpTraceables = new ArrayList<>();
-
- private volatile boolean mEnabled;
- private boolean mFrameScheduled;
-
- private final TraceBuffer.ProtoProvider<P, S, T> mProvider =
- new TraceBuffer.ProtoProvider<P, S, T>() {
- @Override
- public int getItemSize(P proto) {
- return mParams.getProtoSize(proto);
- }
-
- @Override
- public byte[] getBytes(P proto) {
- return mParams.getProtoBytes(proto);
- }
-
- @Override
- public void write(S encapsulatingProto, Queue<T> buffer, OutputStream os)
- throws IOException {
- os.write(mParams.serializeEncapsulatingProto(encapsulatingProto, buffer));
- }
- };
-
- public interface ProtoTraceParams<P, S, T, R> {
- File getTraceFile();
- S getEncapsulatingTraceProto();
- T updateBufferProto(T reuseObj, ArrayList<ProtoTraceable<R>> traceables);
- byte[] serializeEncapsulatingProto(S encapsulatingProto, Queue<T> buffer);
- byte[] getProtoBytes(P proto);
- int getProtoSize(P proto);
- }
-
- public FrameProtoTracer(ProtoTraceParams<P, S, T, R> params) {
- mParams = params;
- mBuffer = new TraceBuffer<>(BUFFER_CAPACITY, mProvider, new Consumer<T>() {
- @Override
- public void accept(T t) {
- onProtoDequeued(t);
- }
- });
- mTraceFile = params.getTraceFile();
- }
-
- public void start() {
- synchronized (mLock) {
- if (mEnabled) {
- return;
- }
- mBuffer.resetBuffer();
- mEnabled = true;
- }
- logState();
- }
-
- public void stop() {
- synchronized (mLock) {
- if (!mEnabled) {
- return;
- }
- mEnabled = false;
- }
- writeToFile();
- }
-
- public boolean isEnabled() {
- return mEnabled;
- }
-
- public void add(ProtoTraceable<R> traceable) {
- synchronized (mLock) {
- mTraceables.add(traceable);
- }
- }
-
- public void remove(ProtoTraceable<R> traceable) {
- synchronized (mLock) {
- mTraceables.remove(traceable);
- }
- }
-
- public void scheduleFrameUpdate() {
- if (!mEnabled || mFrameScheduled) {
- return;
- }
-
- // Schedule an update on the next frame
- if (mChoreographer == null) {
- mChoreographer = Choreographer.getMainThreadInstance();
- }
- mChoreographer.postFrameCallback(this);
- mFrameScheduled = true;
- }
-
- public void update() {
- if (!mEnabled) {
- return;
- }
-
- logState();
- }
-
- public float getBufferUsagePct() {
- return (float) mBuffer.getBufferSize() / BUFFER_CAPACITY;
- }
-
- @Override
- public void doFrame(long frameTimeNanos) {
- logState();
- }
-
- private void onProtoDequeued(T proto) {
- mPool.add(proto);
- }
-
- private void logState() {
- synchronized (mLock) {
- mTmpTraceables.addAll(mTraceables);
- }
-
- mBuffer.add(mParams.updateBufferProto(mPool.poll(), mTmpTraceables));
- mTmpTraceables.clear();
- mFrameScheduled = false;
- }
-
- private void writeToFile() {
- try {
- Trace.beginSection("ProtoTracer.writeToFile");
- mBuffer.writeTraceToFile(mTraceFile, mParams.getEncapsulatingTraceProto());
- } catch (IOException e) {
- Log.e(TAG, "Unable to write buffer to file", e);
- } finally {
- Trace.endSection();
- }
- }
-}
-
-
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/ProtoTraceable.java b/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/ProtoTraceable.java
deleted file mode 100644
index e05b0b0..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/tracing/ProtoTraceable.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.shared.tracing;
-
-/**
- * @see FrameProtoTracer
- */
-public interface ProtoTraceable<T> {
-
- /**
- * NOTE: Implementations should update all fields in this proto.
- */
- void writeToProto(T proto);
-}
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/KeyguardClockFrame.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt
index 635f0fa..50e5466 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockFrame.kt
@@ -12,6 +12,10 @@
) : FrameLayout(context, attrs) {
private var drawAlpha: Int = 255
+ init {
+ setLayerType(View.LAYER_TYPE_SOFTWARE, null)
+ }
+
protected override fun onSetAlpha(alpha: Int): Boolean {
drawAlpha = alpha
return true
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 6c98376..16eb21d 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().toString()); // unregister previous clocks
mDumpManager.registerDumpable(getClass().toString(), 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/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 794e694..b3e08c0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -165,15 +165,18 @@
* Responsible for identifying if PIN hinting is to be enabled or not
*/
private boolean isPinHinting() {
- return mLockPatternUtils.getPinLength(KeyguardUpdateMonitor.getCurrentUser())
- == DEFAULT_PIN_LENGTH;
+ return mPinLength == DEFAULT_PIN_LENGTH;
}
/**
- * Responsible for identifying if auto confirm is enabled or not in Settings
+ * Responsible for identifying if auto confirm is enabled or not in Settings and
+ * a valid PIN_LENGTH is stored on the device (though the latter check is only to make it more
+ * robust since we only allow enabling PIN confirmation if the user has a valid PIN length
+ * saved on device)
*/
private boolean isAutoPinConfirmEnabledInSettings() {
//Checks if user has enabled the auto confirm in Settings
- return mLockPatternUtils.isAutoPinConfirmEnabled(KeyguardUpdateMonitor.getCurrentUser());
+ return mLockPatternUtils.isAutoPinConfirmEnabled(KeyguardUpdateMonitor.getCurrentUser())
+ && mPinLength != LockPatternUtils.PIN_LENGTH_UNAVAILABLE;
}
}
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 518baec..8f03eed 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/keyguard/dagger/KeyguardStatusBarViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
index a7d4455..8762769 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewModule.java
@@ -20,6 +20,7 @@
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
import dagger.Module;
@@ -44,6 +45,13 @@
/** */
@Provides
@KeyguardStatusBarViewScope
+ static StatusBarLocation getStatusBarLocation() {
+ return StatusBarLocation.KEYGUARD;
+ }
+
+ /** */
+ @Provides
+ @KeyguardStatusBarViewScope
static StatusBarUserSwitcherContainer getUserSwitcherContainer(KeyguardStatusBarView view) {
return view.findViewById(R.id.user_switcher_container);
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 1f1b154..04acd0b 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -123,7 +123,6 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.telephony.TelephonyListenerManager;
-import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tuner.TunablePadding.TunablePaddingService;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.DeviceConfigProxy;
@@ -335,7 +334,6 @@
@Inject Lazy<IWallpaperManager> mWallpaperManager;
@Inject Lazy<CommandQueue> mCommandQueue;
@Inject Lazy<RecordingController> mRecordingController;
- @Inject Lazy<ProtoTracer> mProtoTracer;
@Inject Lazy<MediaOutputDialogFactory> mMediaOutputDialogFactory;
@Inject Lazy<DeviceConfigProxy> mDeviceConfigProxy;
@Inject Lazy<TelephonyListenerManager> mTelephonyListenerManager;
@@ -528,7 +526,6 @@
mProviders.put(DozeParameters.class, mDozeParameters::get);
mProviders.put(IWallpaperManager.class, mWallpaperManager::get);
mProviders.put(CommandQueue.class, mCommandQueue::get);
- mProviders.put(ProtoTracer.class, mProtoTracer::get);
mProviders.put(DeviceConfigProxy.class, mDeviceConfigProxy::get);
mProviders.put(TelephonyListenerManager.class, mTelephonyListenerManager::get);
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 1739ba4..baabd95 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -310,6 +310,10 @@
return;
}
scales.put(displayId, scale);
+
+ final MagnificationSettingsController magnificationSettingsController =
+ mMagnificationSettingsSupplier.get(displayId);
+ magnificationSettingsController.setMagnificationScale(scale);
}
@VisibleForTesting
@@ -329,9 +333,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);
}
}
@@ -380,9 +385,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);
}
}
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..6ec5320 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) {
@@ -374,7 +368,7 @@
private void showSettingPanel(boolean resetPosition) {
if (!mIsVisible) {
updateUIControlsIfNeeded();
- setScaleSeekbar(getMagnificationScale());
+ setScaleSeekbar(mScale);
if (resetPosition) {
mDraggableWindowBounds.set(getDraggableWindowBounds());
mParams.x = mDraggableWindowBounds.right;
@@ -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,17 @@
UserHandle.USER_CURRENT);
}
- private float getMagnificationScale() {
- return mSecureSettings.getFloatForUser(
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- SCALE_MIN_VALUE,
- 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 void updateUIControlsIfNeeded() {
@@ -523,10 +519,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..70b4371 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
@@ -58,10 +72,29 @@
val isBypassEnabled: StateFlow<Boolean>
/**
- * Number of consecutively failed authentication attempts. This resets to `0` when
- * authentication succeeds.
+ * Whether the auto confirm feature is enabled for the currently-selected user.
+ *
+ * Note that the length of the PIN is also important to take into consideration, please see
+ * [hintedPinLength].
*/
- val failedAuthenticationAttempts: StateFlow<Int>
+ val isAutoConfirmEnabled: StateFlow<Boolean>
+
+ /**
+ * The exact length a PIN should be for us to enable PIN length hinting.
+ *
+ * A PIN that's shorter or longer than this is not eligible for the UI to render hints showing
+ * how many digits the current PIN is, even if [isAutoConfirmEnabled] is enabled.
+ *
+ * Note that PIN length hinting is only available if the PIN auto confirmation feature is
+ * available.
+ */
+ 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 +102,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,65 +153,146 @@
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> =
- keyguardRepository.isKeyguardUnlocked.stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
- )
+ override val isUnlocked: StateFlow<Boolean> = keyguardRepository.isKeyguardUnlocked
+
+ 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 = false,
+ )
+
+ override val hintedPinLength: Int = 6
+
+ 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..3283e40 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,42 @@
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.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 +84,67 @@
*/
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?> =
+ repository.isAutoConfirmEnabled
+ .map { isAutoConfirmEnabled ->
+ repository.getPinLength().takeIf {
+ isAutoConfirmEnabled && it == repository.hintedPinLength
+ }
+ }
+ .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/battery/AccessorizedBatteryDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt
index b52ddc1..b34f1b4 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/battery/AccessorizedBatteryDrawable.kt
@@ -87,6 +87,10 @@
}
var displayShield: Boolean = false
+ set(value) {
+ field = value
+ postInvalidate()
+ }
private fun updateSizes() {
val b = bounds
@@ -204,4 +208,11 @@
val shieldPathString = context.resources.getString(R.string.config_batterymeterShieldPath)
shieldPath.set(PathParser.createPathFromPathData(shieldPathString))
}
+
+ private val invalidateRunnable: () -> Unit = { invalidateSelf() }
+
+ private fun postInvalidate() {
+ unscheduleSelf(invalidateRunnable)
+ scheduleSelf(invalidateRunnable, 0)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index c1238d9..4e8383c 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -464,9 +464,11 @@
public void dump(PrintWriter pw, String[] args) {
String powerSave = mDrawable == null ? null : mDrawable.getPowerSaveEnabled() + "";
+ String displayShield = mDrawable == null ? null : mDrawable.getDisplayShield() + "";
CharSequence percent = mBatteryPercentView == null ? null : mBatteryPercentView.getText();
pw.println(" BatteryMeterView:");
pw.println(" mDrawable.getPowerSave: " + powerSave);
+ pw.println(" mDrawable.getDisplayShield: " + displayShield);
pw.println(" mBatteryPercentView.getText(): " + percent);
pw.println(" mTextColor: #" + Integer.toHexString(mTextColor));
pw.println(" mBatteryStateUnknown: " + mBatteryStateUnknown);
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index f6a10bd..6a5749c 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -30,16 +30,18 @@
import androidx.annotation.NonNull;
+import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.ViewController;
+import java.io.PrintWriter;
+
import javax.inject.Inject;
/** Controller for {@link BatteryMeterView}. **/
@@ -53,6 +55,7 @@
private final String mSlotBattery;
private final SettingObserver mSettingObserver;
private final UserTracker mUserTracker;
+ private final StatusBarLocation mLocation;
private final ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@@ -94,6 +97,13 @@
public void onIsBatteryDefenderChanged(boolean isBatteryDefender) {
mView.onIsBatteryDefenderChanged(isBatteryDefender);
}
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.print(super.toString());
+ pw.println(" location=" + mLocation);
+ mView.dump(pw, args);
+ }
};
private final UserTracker.Callback mUserChangedCallback =
@@ -113,14 +123,15 @@
@Inject
public BatteryMeterViewController(
BatteryMeterView view,
+ StatusBarLocation location,
UserTracker userTracker,
ConfigurationController configurationController,
TunerService tunerService,
@Main Handler mainHandler,
ContentResolver contentResolver,
- FeatureFlags featureFlags,
BatteryController batteryController) {
super(view);
+ mLocation = location;
mUserTracker = userTracker;
mConfigurationController = configurationController;
mTunerService = tunerService;
@@ -129,7 +140,8 @@
mBatteryController = batteryController;
mView.setBatteryEstimateFetcher(mBatteryController::getEstimatedTimeRemainingString);
- mView.setDisplayShieldEnabled(featureFlags.isEnabled(Flags.BATTERY_SHIELD_ICON));
+ mView.setDisplayShieldEnabled(
+ getContext().getResources().getBoolean(R.bool.flag_battery_shield_icon));
mSlotBattery = getResources().getString(com.android.internal.R.string.status_bar_battery);
mSettingObserver = new SettingObserver(mMainHandler);
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/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricPromptLottieViewWrapper.kt
similarity index 66%
copy from services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java
copy to packages/SystemUI/src/com/android/systemui/biometrics/BiometricPromptLottieViewWrapper.kt
index 6727fbc..e48e6e2 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricPromptLottieViewWrapper.kt
@@ -13,13 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.systemui.biometrics
-package com.android.server.biometrics;
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
-/**
- * Interface for biometric operations to get camera privacy state.
- */
-public interface BiometricSensorPrivacy {
- /* Returns true if privacy is enabled and camera access is disabled. */
- boolean isCameraPrivacyEnabled();
-}
+class BiometricPromptLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 9d0cde1..083e21f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -17,12 +17,7 @@
import android.app.ActivityTaskManager
import android.content.Context
-import android.content.res.Configuration
-import android.graphics.Color
import android.graphics.PixelFormat
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffColorFilter
-import android.graphics.Rect
import android.hardware.biometrics.BiometricOverlayConstants
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
@@ -33,27 +28,23 @@
import android.hardware.fingerprint.ISidefpsController
import android.os.Handler
import android.util.Log
-import android.util.RotationUtils
import android.view.Display
import android.view.DisplayInfo
import android.view.Gravity
import android.view.LayoutInflater
import android.view.Surface
import android.view.View
-import android.view.View.AccessibilityDelegate
import android.view.ViewPropertyAnimator
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
-import android.view.accessibility.AccessibilityEvent
-import androidx.annotation.RawRes
import com.airbnb.lottie.LottieAnimationView
-import com.airbnb.lottie.LottieProperty
-import com.airbnb.lottie.model.KeyPath
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.ui.binder.SideFpsOverlayViewBinder
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -64,6 +55,7 @@
import com.android.systemui.util.traceSection
import java.io.PrintWriter
import javax.inject.Inject
+import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -86,6 +78,7 @@
@Main private val mainExecutor: DelayableExecutor,
@Main private val handler: Handler,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
+ private val sideFpsOverlayViewModelFactory: Provider<SideFpsOverlayViewModel>,
@Application private val scope: CoroutineScope,
dumpManager: DumpManager
) : Dumpable {
@@ -117,6 +110,8 @@
private var overlayView: View? = null
set(value) {
field?.let { oldView ->
+ val lottie = oldView.findViewById(R.id.sidefps_animation) as LottieAnimationView
+ lottie.pauseAnimation()
windowManager.removeView(oldView)
orientationListener.disable()
}
@@ -193,7 +188,9 @@
requests.add(request)
mainExecutor.execute {
if (overlayView == null) {
- traceSection("SideFpsController#show(request=${request.name}, reason=$reason") {
+ traceSection(
+ "SideFpsController#show(request=${request.name}, reason=$reason)"
+ ) {
createOverlayForDisplay(reason)
}
} else {
@@ -208,7 +205,7 @@
requests.remove(request)
mainExecutor.execute {
if (requests.isEmpty()) {
- traceSection("SideFpsController#hide(${request.name}") { overlayView = null }
+ traceSection("SideFpsController#hide(${request.name})") { overlayView = null }
}
}
}
@@ -246,105 +243,15 @@
private fun createOverlayForDisplay(@BiometricOverlayConstants.ShowReason reason: Int) {
val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
overlayView = view
- val display = context.display!!
- // b/284098873 `context.display.rotation` may not up-to-date, we use displayInfo.rotation
- display.getDisplayInfo(displayInfo)
- val offsets =
- sensorProps.getLocation(display.uniqueId).let { location ->
- if (location == null) {
- Log.w(TAG, "No location specified for display: ${display.uniqueId}")
- }
- location ?: sensorProps.location
- }
- overlayOffsets = offsets
-
- val lottie = view.findViewById(R.id.sidefps_animation) as LottieAnimationView
- view.rotation =
- display.asSideFpsAnimationRotation(
- offsets.isYAligned(),
- getRotationFromDefault(displayInfo.rotation)
- )
- lottie.setAnimation(
- display.asSideFpsAnimation(
- offsets.isYAligned(),
- getRotationFromDefault(displayInfo.rotation)
- )
+ SideFpsOverlayViewBinder.bind(
+ view = view,
+ viewModel = sideFpsOverlayViewModelFactory.get(),
+ overlayViewParams = overlayViewParams,
+ reason = reason,
+ context = context,
)
- lottie.addLottieOnCompositionLoadedListener {
- // Check that view is not stale, and that overlayView has not been hidden/removed
- if (overlayView != null && overlayView == view) {
- updateOverlayParams(display, it.bounds)
- }
- }
orientationReasonListener.reason = reason
- lottie.addOverlayDynamicColor(context, reason)
-
- /**
- * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from
- * speaking @string/accessibility_fingerprint_label twice when sensor location indicator is
- * in focus
- */
- view.setAccessibilityDelegate(
- object : AccessibilityDelegate() {
- override fun dispatchPopulateAccessibilityEvent(
- host: View,
- event: AccessibilityEvent
- ): Boolean {
- return if (
- event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
- ) {
- true
- } else {
- super.dispatchPopulateAccessibilityEvent(host, event)
- }
- }
- }
- )
}
-
- @VisibleForTesting
- fun updateOverlayParams(display: Display, bounds: Rect) {
- val isNaturalOrientation = display.isNaturalOrientation()
- val isDefaultOrientation =
- if (isReverseDefaultRotation) !isNaturalOrientation else isNaturalOrientation
- val size = windowManager.maximumWindowMetrics.bounds
-
- val displayWidth = if (isDefaultOrientation) size.width() else size.height()
- val displayHeight = if (isDefaultOrientation) size.height() else size.width()
- val boundsWidth = if (isDefaultOrientation) bounds.width() else bounds.height()
- val boundsHeight = if (isDefaultOrientation) bounds.height() else bounds.width()
-
- val sensorBounds =
- if (overlayOffsets.isYAligned()) {
- Rect(
- displayWidth - boundsWidth,
- overlayOffsets.sensorLocationY,
- displayWidth,
- overlayOffsets.sensorLocationY + boundsHeight
- )
- } else {
- Rect(
- overlayOffsets.sensorLocationX,
- 0,
- overlayOffsets.sensorLocationX + boundsWidth,
- boundsHeight
- )
- }
-
- RotationUtils.rotateBounds(
- sensorBounds,
- Rect(0, 0, displayWidth, displayHeight),
- getRotationFromDefault(display.rotation)
- )
-
- overlayViewParams.x = sensorBounds.left
- overlayViewParams.y = sensorBounds.top
-
- windowManager.updateViewLayout(overlayView, overlayViewParams)
- }
-
- private fun getRotationFromDefault(rotation: Int): Int =
- if (isReverseDefaultRotation) (rotation + 1) % 4 else rotation
}
private val FingerprintManager?.sideFpsSensorProperties: FingerprintSensorPropertiesInternal?
@@ -369,89 +276,12 @@
private fun ActivityTaskManager.topClass(): String =
getTasks(1).firstOrNull()?.topActivity?.className ?: ""
-@RawRes
-private fun Display.asSideFpsAnimation(yAligned: Boolean, rotationFromDefault: Int): Int =
- when (rotationFromDefault) {
- Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape
- Surface.ROTATION_180 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape
- else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse
- }
-
-private fun Display.asSideFpsAnimationRotation(yAligned: Boolean, rotationFromDefault: Int): Float =
- when (rotationFromDefault) {
- Surface.ROTATION_90 -> if (yAligned) 0f else 180f
- Surface.ROTATION_180 -> 180f
- Surface.ROTATION_270 -> if (yAligned) 180f else 0f
- else -> 0f
- }
-
private fun SensorLocationInternal.isYAligned(): Boolean = sensorLocationY != 0
private fun Display.isNaturalOrientation(): Boolean =
rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
-private fun LottieAnimationView.addOverlayDynamicColor(
- context: Context,
- @BiometricOverlayConstants.ShowReason reason: Int
-) {
- fun update() {
- val isKeyguard = reason == REASON_AUTH_KEYGUARD
- if (isKeyguard) {
- val color =
- com.android.settingslib.Utils.getColorAttrDefaultColor(
- context,
- com.android.internal.R.attr.materialColorPrimaryFixed
- )
- val outerRimColor =
- com.android.settingslib.Utils.getColorAttrDefaultColor(
- context,
- com.android.internal.R.attr.materialColorPrimaryFixedDim
- )
- val chevronFill =
- com.android.settingslib.Utils.getColorAttrDefaultColor(
- context,
- com.android.internal.R.attr.materialColorOnPrimaryFixed
- )
- addValueCallback(KeyPath(".blue600", "**"), LottieProperty.COLOR_FILTER) {
- PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
- }
- addValueCallback(KeyPath(".blue400", "**"), LottieProperty.COLOR_FILTER) {
- PorterDuffColorFilter(outerRimColor, PorterDuff.Mode.SRC_ATOP)
- }
- addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
- PorterDuffColorFilter(chevronFill, PorterDuff.Mode.SRC_ATOP)
- }
- } else {
- if (!isDarkMode(context)) {
- addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
- PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP)
- }
- }
- for (key in listOf(".blue600", ".blue400")) {
- addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) {
- PorterDuffColorFilter(
- context.getColor(R.color.settingslib_color_blue400),
- PorterDuff.Mode.SRC_ATOP
- )
- }
- }
- }
- }
-
- if (composition != null) {
- update()
- } else {
- addLottieOnCompositionLoadedListener { update() }
- }
-}
-
-private fun isDarkMode(context: Context): Boolean {
- val darkMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
- return darkMode == Configuration.UI_MODE_NIGHT_YES
-}
-
-@VisibleForTesting
-class OrientationReasonListener(
+public class OrientationReasonListener(
context: Context,
displayManager: DisplayManager,
handler: Handler,
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
similarity index 66%
copy from packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
copy to packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
index dd89441..e98f6db 100644
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.systemui.biometrics
-/**
- * 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;
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
+
+class SideFpsLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
index c43722f..efbde4c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FingerprintPropertyRepository.kt
@@ -16,8 +16,11 @@
package com.android.systemui.biometrics.data.repository
+import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.biometrics.SensorProperties
import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
@@ -30,10 +33,8 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
/**
@@ -43,22 +44,17 @@
*/
interface FingerprintPropertyRepository {
- /**
- * If the repository is initialized or not. Other properties are defaults until this is true.
- */
- val isInitialized: Flow<Boolean>
-
/** The id of fingerprint sensor. */
- val sensorId: StateFlow<Int>
+ val sensorId: Flow<Int>
/** The security strength of sensor (convenience, weak, strong). */
- val strength: StateFlow<SensorStrength>
+ val strength: Flow<SensorStrength>
/** The types of fingerprint sensor (rear, ultrasonic, optical, etc.). */
- val sensorType: StateFlow<FingerprintSensorType>
+ val sensorType: Flow<FingerprintSensorType>
/** The sensor location relative to each physical display. */
- val sensorLocations: StateFlow<Map<String, SensorLocationInternal>>
+ val sensorLocations: Flow<Map<String, SensorLocationInternal>>
}
@SysUISingleton
@@ -66,10 +62,10 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val fingerprintManager: FingerprintManager
+ private val fingerprintManager: FingerprintManager?
) : FingerprintPropertyRepository {
- override val isInitialized: Flow<Boolean> =
+ private val props: Flow<FingerprintSensorPropertiesInternal> =
conflatedCallbackFlow {
val callback =
object : IFingerprintAuthenticatorsRegisteredCallback.Stub() {
@@ -77,45 +73,47 @@
sensors: List<FingerprintSensorPropertiesInternal>
) {
if (sensors.isNotEmpty()) {
- setProperties(sensors[0])
- trySendWithFailureLogging(true, TAG, "initialize properties")
+ trySendWithFailureLogging(sensors[0], TAG, "initialize properties")
+ } else {
+ trySendWithFailureLogging(
+ DEFAULT_PROPS,
+ TAG,
+ "initialize with default properties"
+ )
}
}
}
- fingerprintManager.addAuthenticatorsRegisteredCallback(callback)
- trySendWithFailureLogging(false, TAG, "initial value defaulting to false")
+ fingerprintManager?.addAuthenticatorsRegisteredCallback(callback)
+ trySendWithFailureLogging(DEFAULT_PROPS, TAG, "initialize with default properties")
awaitClose {}
}
.shareIn(scope = applicationScope, started = SharingStarted.Eagerly, replay = 1)
- private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
- override val sensorId: StateFlow<Int> = _sensorId.asStateFlow()
-
- private val _strength: MutableStateFlow<SensorStrength> =
- MutableStateFlow(SensorStrength.CONVENIENCE)
- override val strength = _strength.asStateFlow()
-
- private val _sensorType: MutableStateFlow<FingerprintSensorType> =
- MutableStateFlow(FingerprintSensorType.UNKNOWN)
- override val sensorType = _sensorType.asStateFlow()
-
- private val _sensorLocations: MutableStateFlow<Map<String, SensorLocationInternal>> =
- MutableStateFlow(mapOf("" to SensorLocationInternal.DEFAULT))
- override val sensorLocations: StateFlow<Map<String, SensorLocationInternal>> =
- _sensorLocations.asStateFlow()
-
- private fun setProperties(prop: FingerprintSensorPropertiesInternal) {
- _sensorId.value = prop.sensorId
- _strength.value = sensorStrengthIntToObject(prop.sensorStrength)
- _sensorType.value = sensorTypeIntToObject(prop.sensorType)
- _sensorLocations.value =
- prop.allLocations.associateBy { sensorLocationInternal ->
+ override val sensorId: Flow<Int> = props.map { it.sensorId }
+ override val strength: Flow<SensorStrength> =
+ props.map { sensorStrengthIntToObject(it.sensorStrength) }
+ override val sensorType: Flow<FingerprintSensorType> =
+ props.map { sensorTypeIntToObject(it.sensorType) }
+ override val sensorLocations: Flow<Map<String, SensorLocationInternal>> =
+ props.map {
+ it.allLocations.associateBy { sensorLocationInternal ->
sensorLocationInternal.displayId
}
- }
+ }
companion object {
private const val TAG = "FingerprintPropertyRepositoryImpl"
+ private val DEFAULT_PROPS =
+ FingerprintSensorPropertiesInternal(
+ -1 /* sensorId */,
+ SensorProperties.STRENGTH_CONVENIENCE,
+ 0 /* maxEnrollmentsPerUser */,
+ listOf<ComponentInfoInternal>(),
+ FingerprintSensorProperties.TYPE_UNKNOWN,
+ false /* halControlsIllumination */,
+ true /* resetLockoutRequiresHardwareAuthToken */,
+ listOf<SensorLocationInternal>(SensorLocationInternal.DEFAULT)
+ )
}
}
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/interactor/SideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
index aa85e5f3..37f39cb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractor.kt
@@ -17,16 +17,24 @@
package com.android.systemui.biometrics.domain.interactor
import android.hardware.biometrics.SensorLocationInternal
-import android.util.Log
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
/** Business logic for SideFps overlay offsets. */
interface SideFpsOverlayInteractor {
+ /** The displayId of the current display. */
+ val displayId: Flow<String>
- /** Get the corresponding offsets based on different displayId. */
- fun getOverlayOffsets(displayId: String): SensorLocationInternal
+ /** The corresponding offsets based on different displayId. */
+ val overlayOffsets: Flow<SensorLocationInternal>
+
+ /** Update the displayId. */
+ fun changeDisplay(displayId: String?)
}
@SysUISingleton
@@ -35,14 +43,16 @@
constructor(private val fingerprintPropertyRepository: FingerprintPropertyRepository) :
SideFpsOverlayInteractor {
- override fun getOverlayOffsets(displayId: String): SensorLocationInternal {
- val offsets = fingerprintPropertyRepository.sensorLocations.value
- return if (offsets.containsKey(displayId)) {
- offsets[displayId]!!
- } else {
- Log.w(TAG, "No location specified for display: $displayId")
- offsets[""]!!
+ private val _displayId: MutableStateFlow<String> = MutableStateFlow("")
+ override val displayId: Flow<String> = _displayId.asStateFlow()
+
+ override val overlayOffsets: Flow<SensorLocationInternal> =
+ combine(displayId, fingerprintPropertyRepository.sensorLocations) { displayId, offsets ->
+ offsets[displayId] ?: SensorLocationInternal.DEFAULT
}
+
+ override fun changeDisplay(displayId: String?) {
+ _displayId.value = displayId ?: ""
}
companion object {
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/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
new file mode 100644
index 0000000..0409519
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.biometrics.ui.binder
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Color
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.hardware.biometrics.BiometricOverlayConstants
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityEvent
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.LottieProperty
+import com.airbnb.lottie.model.KeyPath
+import com.android.systemui.R
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.lifecycle.repeatWhenAttached
+import kotlinx.coroutines.launch
+
+/** Sub-binder for SideFpsOverlayView. */
+object SideFpsOverlayViewBinder {
+
+ /** Bind the view. */
+ @JvmStatic
+ fun bind(
+ view: View,
+ viewModel: SideFpsOverlayViewModel,
+ overlayViewParams: WindowManager.LayoutParams,
+ @BiometricOverlayConstants.ShowReason reason: Int,
+ @Application context: Context
+ ) {
+ val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+
+ val lottie = view.findViewById(R.id.sidefps_animation) as LottieAnimationView
+
+ viewModel.changeDisplay()
+
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.sideFpsAnimationRotation.collect { rotation ->
+ view.rotation = rotation
+ }
+ }
+
+ launch {
+ // TODO(b/221037350, wenhuiy): Create a separate ViewBinder for sideFpsAnimation
+ // in order to add scuba tests in the future.
+ viewModel.sideFpsAnimation.collect { animation ->
+ lottie.setAnimation(animation)
+ }
+ }
+
+ launch {
+ viewModel.sensorBounds.collect { sensorBounds ->
+ overlayViewParams.x = sensorBounds.left
+ overlayViewParams.y = sensorBounds.top
+
+ windowManager.updateViewLayout(view, overlayViewParams)
+ }
+ }
+
+ launch {
+ viewModel.overlayOffsets.collect { overlayOffsets ->
+ lottie.addLottieOnCompositionLoadedListener {
+ viewModel.updateSensorBounds(
+ it.bounds,
+ windowManager.maximumWindowMetrics.bounds,
+ overlayOffsets
+ )
+ }
+ }
+ }
+ }
+ }
+
+ lottie.addOverlayDynamicColor(context, reason)
+
+ /**
+ * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from
+ * speaking @string/accessibility_fingerprint_label twice when sensor location indicator is
+ * in focus
+ */
+ view.accessibilityDelegate =
+ object : View.AccessibilityDelegate() {
+ override fun dispatchPopulateAccessibilityEvent(
+ host: View,
+ event: AccessibilityEvent
+ ): Boolean {
+ return if (
+ event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+ ) {
+ true
+ } else {
+ super.dispatchPopulateAccessibilityEvent(host, event)
+ }
+ }
+ }
+ }
+}
+
+private fun LottieAnimationView.addOverlayDynamicColor(
+ context: Context,
+ @BiometricOverlayConstants.ShowReason reason: Int
+) {
+ fun update() {
+ val isKeyguard = reason == BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ if (isKeyguard) {
+ val color = context.getColor(R.color.numpad_key_color_secondary) // match bouncer color
+ val chevronFill =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ context,
+ android.R.attr.textColorPrimaryInverse
+ )
+ for (key in listOf(".blue600", ".blue400")) {
+ addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
+ }
+ }
+ addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(chevronFill, PorterDuff.Mode.SRC_ATOP)
+ }
+ } else if (!isDarkMode(context)) {
+ addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP)
+ }
+ } else if (isDarkMode(context)) {
+ for (key in listOf(".blue600", ".blue400")) {
+ addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(
+ context.getColor(R.color.settingslib_color_blue400),
+ PorterDuff.Mode.SRC_ATOP
+ )
+ }
+ }
+ }
+ }
+
+ if (composition != null) {
+ update()
+ } else {
+ addLottieOnCompositionLoadedListener { update() }
+ }
+}
+
+private fun isDarkMode(context: Context): Boolean {
+ val darkMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ return darkMode == Configuration.UI_MODE_NIGHT_YES
+}
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/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
new file mode 100644
index 0000000..e938b4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.ui.viewmodel
+
+import android.content.Context
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.util.RotationUtils
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.Surface
+import androidx.annotation.RawRes
+import com.android.systemui.R
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.map
+
+/** View-model for SideFpsOverlayView. */
+class SideFpsOverlayViewModel
+@Inject
+constructor(
+ @Application private val context: Context,
+ private val sideFpsOverlayInteractor: SideFpsOverlayInteractor,
+) {
+
+ private val isReverseDefaultRotation =
+ context.resources.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)
+
+ private val _sensorBounds: MutableStateFlow<Rect> = MutableStateFlow(Rect())
+ val sensorBounds = _sensorBounds.asStateFlow()
+
+ val overlayOffsets: Flow<SensorLocationInternal> = sideFpsOverlayInteractor.overlayOffsets
+
+ /** Update the displayId. */
+ fun changeDisplay() {
+ sideFpsOverlayInteractor.changeDisplay(context.display!!.uniqueId)
+ }
+
+ /** Determine the rotation of the sideFps animation given the overlay offsets. */
+ val sideFpsAnimationRotation: Flow<Float> =
+ overlayOffsets.map { overlayOffsets ->
+ val display = context.display!!
+ val displayInfo: DisplayInfo = DisplayInfo()
+ // b/284098873 `context.display.rotation` may not up-to-date, we use
+ // displayInfo.rotation
+ display.getDisplayInfo(displayInfo)
+ val yAligned: Boolean = overlayOffsets.isYAligned()
+ when (getRotationFromDefault(displayInfo.rotation)) {
+ Surface.ROTATION_90 -> if (yAligned) 0f else 180f
+ Surface.ROTATION_180 -> 180f
+ Surface.ROTATION_270 -> if (yAligned) 180f else 0f
+ else -> 0f
+ }
+ }
+
+ /** Populate the sideFps animation from the overlay offsets. */
+ @RawRes
+ val sideFpsAnimation: Flow<Int> =
+ overlayOffsets.map { overlayOffsets ->
+ val display = context.display!!
+ val displayInfo: DisplayInfo = DisplayInfo()
+ // b/284098873 `context.display.rotation` may not up-to-date, we use
+ // displayInfo.rotation
+ display.getDisplayInfo(displayInfo)
+ val yAligned: Boolean = overlayOffsets.isYAligned()
+ when (getRotationFromDefault(displayInfo.rotation)) {
+ Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape
+ Surface.ROTATION_180 ->
+ if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape
+ else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse
+ }
+ }
+
+ /**
+ * Calculate and update the bounds of the sensor based on the bounds of the overlay view, the
+ * maximum bounds of the window, and the offsets of the sensor location.
+ */
+ fun updateSensorBounds(
+ bounds: Rect,
+ maximumWindowBounds: Rect,
+ offsets: SensorLocationInternal
+ ) {
+ val isNaturalOrientation = context.display!!.isNaturalOrientation()
+ val isDefaultOrientation =
+ if (isReverseDefaultRotation) !isNaturalOrientation else isNaturalOrientation
+
+ val displayWidth =
+ if (isDefaultOrientation) maximumWindowBounds.width() else maximumWindowBounds.height()
+ val displayHeight =
+ if (isDefaultOrientation) maximumWindowBounds.height() else maximumWindowBounds.width()
+ val boundsWidth = if (isDefaultOrientation) bounds.width() else bounds.height()
+ val boundsHeight = if (isDefaultOrientation) bounds.height() else bounds.width()
+
+ val sensorBounds =
+ if (offsets.isYAligned()) {
+ Rect(
+ displayWidth - boundsWidth,
+ offsets.sensorLocationY,
+ displayWidth,
+ offsets.sensorLocationY + boundsHeight
+ )
+ } else {
+ Rect(
+ offsets.sensorLocationX,
+ 0,
+ offsets.sensorLocationX + boundsWidth,
+ boundsHeight
+ )
+ }
+
+ val displayInfo: DisplayInfo = DisplayInfo()
+ context.display!!.getDisplayInfo(displayInfo)
+
+ RotationUtils.rotateBounds(
+ sensorBounds,
+ Rect(0, 0, displayWidth, displayHeight),
+ getRotationFromDefault(displayInfo.rotation)
+ )
+
+ _sensorBounds.value = sensorBounds
+ }
+
+ private fun getRotationFromDefault(rotation: Int): Int =
+ if (isReverseDefaultRotation) (rotation + 1) % 4 else rotation
+}
+
+private fun Display.isNaturalOrientation(): Boolean =
+ rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
+
+private fun SensorLocationInternal.isYAligned(): Boolean = sensorLocationY != 0
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..8e14237 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 hinted PIN, or `null`, if pin length hint should not be shown. */
+ 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/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index d73c85b..776b336e 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 a90980f..046ccf16 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -18,6 +18,7 @@
import com.android.systemui.globalactions.ShutdownUiModule;
import com.android.systemui.keyguard.CustomizationProvider;
+import com.android.systemui.shade.ShadeModule;
import com.android.systemui.statusbar.NotificationInsetsModule;
import com.android.systemui.statusbar.QsFrameTranslateModule;
@@ -32,6 +33,7 @@
DependencyProvider.class,
NotificationInsetsModule.class,
QsFrameTranslateModule.class,
+ ShadeModule.class,
ShutdownUiModule.class,
SystemUIBinder.class,
SystemUIModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 3b89739..3c42a29 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -82,7 +82,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;
@@ -199,7 +198,6 @@
SecurityRepositoryModule.class,
ScreenRecordModule.class,
SettingsUtilModule.class,
- ShadeModule.class,
SmartRepliesInflationModule.class,
SmartspaceModule.class,
StatusBarPipelineModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index ee046c2..484bf3d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -26,6 +26,7 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.animation.Interpolators
+import com.android.dream.lowlight.util.TruncatedInterpolator
import com.android.systemui.R
import com.android.systemui.complication.ComplicationHostViewController
import com.android.systemui.complication.ComplicationLayoutParams
@@ -204,31 +205,28 @@
translationYAnimator(
from = 0f,
to = -mDreamInTranslationYDistance.toFloat(),
- durationMs = mDreamInTranslationYDurationMs,
+ durationMs = mDreamInComplicationsAnimDurationMs,
delayMs = 0,
- interpolator = Interpolators.EMPHASIZED
+ // Truncate the animation from the full duration to match the alpha
+ // animation so that the whole animation ends at the same time.
+ interpolator =
+ TruncatedInterpolator(
+ Interpolators.EMPHASIZED,
+ /*originalDuration=*/ mDreamInTranslationYDurationMs.toFloat(),
+ /*newDuration=*/ mDreamInComplicationsAnimDurationMs.toFloat()
+ )
),
alphaAnimator(
- from =
- mCurrentAlphaAtPosition.getOrDefault(
- key = POSITION_BOTTOM,
- defaultValue = 1f
- ),
- to = 0f,
- durationMs = mDreamInComplicationsAnimDurationMs,
- delayMs = 0,
- positions = POSITION_BOTTOM
- )
- .apply {
- doOnEnd {
- // The logical end of the animation is once the alpha and blur
- // animations finish, end the animation so that any listeners are
- // notified. The Y translation animation is much longer than all of
- // the other animations due to how the spec is defined, but is not
- // expected to run to completion.
- mAnimator?.end()
- }
- },
+ from =
+ mCurrentAlphaAtPosition.getOrDefault(
+ key = POSITION_BOTTOM,
+ defaultValue = 1f
+ ),
+ to = 0f,
+ durationMs = mDreamInComplicationsAnimDurationMs,
+ delayMs = 0,
+ positions = POSITION_BOTTOM
+ ),
alphaAnimator(
from =
mCurrentAlphaAtPosition.getOrDefault(
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f892a97..add32398 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -61,10 +61,6 @@
// TODO(b/254512538): Tracking Bug
val INSTANT_VOICE_REPLY = unreleasedFlag(111, "instant_voice_reply")
- // TODO(b/279735475): Tracking Bug
- @JvmField
- val NEW_LIGHT_BAR_LOGIC = releasedFlag(279735475, "new_light_bar_logic")
-
/**
* This flag is server-controlled and should stay as [unreleasedFlag] since we never want to
* enable it on release builds.
@@ -72,9 +68,6 @@
val NOTIFICATION_MEMORY_LOGGING_ENABLED =
unreleasedFlag(119, "notification_memory_logging_enabled")
- // TODO(b/257315550): Tracking Bug
- val NO_HUN_FOR_OLD_WHEN = releasedFlag(118, "no_hun_for_old_when")
-
// TODO(b/260335638): Tracking Bug
@JvmField
val NOTIFICATION_INLINE_REPLY_ANIMATION =
@@ -91,6 +84,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 =
@@ -169,16 +167,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.
*/
@@ -268,6 +256,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
@@ -285,7 +283,16 @@
/** Migrate the lock icon view to the new keyguard root view. */
// TODO(b/286552209): Tracking bug.
@JvmField
- val MIGRATE_LOCK_ICON = unreleasedFlag(240, "migrate_lock_icon")
+ val MIGRATE_LOCK_ICON = unreleasedFlag(240, "migrate_lock_icon", teamfood = true)
+
+ // TODO(b/288276738): Tracking bug.
+ @JvmField
+ val WIDGET_ON_KEYGUARD = unreleasedFlag(241, "widget_on_keyguard")
+
+ /** Migrate the NSSL to the a sibling to both the panel and keyguard root view. */
+ // TODO(b/288074305): Tracking bug.
+ @JvmField
+ val MIGRATE_NSSL = unreleasedFlag(242, "migrate_nssl")
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@@ -358,22 +365,10 @@
// TODO(b/256614753): Tracking Bug
val NEW_STATUS_BAR_MOBILE_ICONS = releasedFlag(606, "new_status_bar_mobile_icons")
- // TODO(b/256614210): Tracking Bug
- val NEW_STATUS_BAR_WIFI_ICON = releasedFlag(607, "new_status_bar_wifi_icon")
-
// TODO(b/256614751): Tracking Bug
val NEW_STATUS_BAR_MOBILE_ICONS_BACKEND =
unreleasedFlag(608, "new_status_bar_mobile_icons_backend", teamfood = true)
- // TODO(b/256613548): Tracking Bug
- val NEW_STATUS_BAR_WIFI_ICON_BACKEND =
- unreleasedFlag(609, "new_status_bar_wifi_icon_backend", teamfood = true)
-
- // TODO(b/256623670): Tracking Bug
- @JvmField
- val BATTERY_SHIELD_ICON =
- resourceBooleanFlag(610, R.bool.flag_battery_shield_icon, "battery_shield_icon")
-
// TODO(b/260881289): Tracking Bug
val NEW_STATUS_BAR_ICONS_DEBUG_COLORING =
unreleasedFlag(611, "new_status_bar_icons_debug_coloring")
@@ -704,11 +699,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
@@ -780,9 +775,21 @@
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
@JvmField
val USE_REPOS_FOR_BOUNCER_SHOWING = unreleasedFlag(2900, "use_repos_for_bouncer_showing")
+
+ // 3100 - Haptic interactions
+
+ // TODO(b/290213663): Tracking Bug
+ @JvmField
+ val ONE_WAY_HAPTICS_API_MIGRATION =
+ unreleasedFlag(3100, "oneway_haptics_api_migration")
}
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 61bacbda..29a2d12 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -50,7 +50,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;
@@ -91,7 +90,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..d119920 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
@@ -87,7 +87,7 @@
val isKeyguardShowing: Flow<Boolean>
/** Is the keyguard in a unlocked state? */
- val isKeyguardUnlocked: Flow<Boolean>
+ val isKeyguardUnlocked: StateFlow<Boolean>
/** Is an activity showing over the keyguard? */
val isKeyguardOccluded: Flow<Boolean>
@@ -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. */
@@ -294,7 +299,7 @@
}
.distinctUntilChanged()
- override val isKeyguardUnlocked: Flow<Boolean> =
+ override val isKeyguardUnlocked: StateFlow<Boolean> =
conflatedCallbackFlow {
val callback =
object : KeyguardStateController.Callback {
@@ -325,7 +330,11 @@
awaitClose { keyguardStateController.removeCallback(callback) }
}
- .distinctUntilChanged()
+ .stateIn(
+ scope = scope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = keyguardStateController.isUnlocked,
+ )
override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
val callback =
@@ -610,6 +619,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 +640,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/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/UdfpsLottieViewWrapper.kt
similarity index 66%
copy from packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
copy to packages/SystemUI/src/com/android/systemui/keyguard/ui/view/UdfpsLottieViewWrapper.kt
index dd89441..3a2c3c7 100644
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/UdfpsLottieViewWrapper.kt
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.systemui.keyguard.ui.view
-/**
- * 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;
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
+
+class UdfpsLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
index a4f4076..a437139 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
@@ -16,15 +16,19 @@
package com.android.systemui.mediaprojection.taskswitcher.ui
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
import android.content.Context
import android.util.Log
-import android.widget.Toast
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.NotShowing
import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.Showing
import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
+import com.android.systemui.util.NotificationChannels
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -37,38 +41,69 @@
@Inject
constructor(
private val context: Context,
+ private val notificationManager: NotificationManager,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
private val viewModel: TaskSwitcherNotificationViewModel,
) {
-
fun start() {
applicationScope.launch {
viewModel.uiState.flowOn(mainDispatcher).collect { uiState ->
Log.d(TAG, "uiState -> $uiState")
when (uiState) {
- is Showing -> showNotification(uiState)
+ is Showing -> showNotification()
is NotShowing -> hideNotification()
}
}
}
}
- private fun showNotification(uiState: Showing) {
- val text =
- """
- Sharing pauses when you switch apps.
- Share this app instead.
- Switch back.
- """
- .trimIndent()
- // TODO(b/286201515): Create actual notification.
- Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
+ private fun showNotification() {
+ notificationManager.notify(TAG, NOTIFICATION_ID, createNotification())
}
- private fun hideNotification() {}
+ private fun createNotification(): Notification {
+ // TODO(b/286201261): implement actions
+ val actionSwitch =
+ Notification.Action.Builder(
+ /* icon = */ null,
+ context.getString(R.string.media_projection_task_switcher_action_switch),
+ /* intent = */ null
+ )
+ .build()
+
+ val actionBack =
+ Notification.Action.Builder(
+ /* icon = */ null,
+ context.getString(R.string.media_projection_task_switcher_action_back),
+ /* intent = */ null
+ )
+ .build()
+
+ val channel =
+ NotificationChannel(
+ NotificationChannels.HINTS,
+ context.getString(R.string.media_projection_task_switcher_notification_channel),
+ NotificationManager.IMPORTANCE_HIGH
+ )
+ notificationManager.createNotificationChannel(channel)
+ return Notification.Builder(context, channel.id)
+ .setSmallIcon(R.drawable.qs_screen_record_icon_on)
+ .setAutoCancel(true)
+ .setContentText(context.getString(R.string.media_projection_task_switcher_text))
+ .addAction(actionSwitch)
+ .addAction(actionBack)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setDefaults(Notification.DEFAULT_VIBRATE)
+ .build()
+ }
+
+ private fun hideNotification() {
+ notificationManager.cancel(NOTIFICATION_ID)
+ }
companion object {
private const val TAG = "TaskSwitchNotifCoord"
+ private const val NOTIFICATION_ID = 5566
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index a8af67a..b21b001 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -88,11 +88,7 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.statusbar.phone.LightBarController;
-import com.android.systemui.tracing.ProtoTracer;
-import com.android.systemui.tracing.nano.EdgeBackGestureHandlerProto;
-import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.systemui.util.Assert;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.desktopmode.DesktopMode;
@@ -115,8 +111,7 @@
/**
* Utility class to handle edge swipes for back gesture
*/
-public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBackPlugin>,
- ProtoTraceable<SystemUiTraceProto> {
+public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBackPlugin> {
private static final String TAG = "EdgeBackGestureHandler";
private static final int MAX_LONG_PRESS_TIMEOUT = SystemProperties.getInt(
@@ -192,7 +187,6 @@
private Consumer<Boolean> mButtonForcedVisibleCallback;
private final PluginManager mPluginManager;
- private final ProtoTracer mProtoTracer;
private final NavigationModeController mNavigationModeController;
private final BackPanelController.Factory mBackPanelControllerFactory;
private final ViewConfiguration mViewConfiguration;
@@ -402,7 +396,6 @@
@Main Handler handler,
@Background Executor backgroundExecutor,
UserTracker userTracker,
- ProtoTracer protoTracer,
NavigationModeController navigationModeController,
BackPanelController.Factory backPanelControllerFactory,
ViewConfiguration viewConfiguration,
@@ -425,7 +418,6 @@
mOverviewProxyService = overviewProxyService;
mSysUiState = sysUiState;
mPluginManager = pluginManager;
- mProtoTracer = protoTracer;
mNavigationModeController = navigationModeController;
mBackPanelControllerFactory = backPanelControllerFactory;
mViewConfiguration = viewConfiguration;
@@ -557,7 +549,6 @@
*/
public void onNavBarAttached() {
mIsAttached = true;
- mProtoTracer.add(this);
mOverviewProxyService.addCallback(mQuickSwitchListener);
mSysUiState.addCallback(mSysUiStateCallback);
if (mIsTrackpadGestureFeaturesEnabled) {
@@ -576,7 +567,6 @@
*/
public void onNavBarDetached() {
mIsAttached = false;
- mProtoTracer.remove(this);
mOverviewProxyService.removeCallback(mQuickSwitchListener);
mSysUiState.removeCallback(mSysUiStateCallback);
mInputManager.unregisterInputDeviceListener(mInputDeviceListener);
@@ -1135,8 +1125,6 @@
dispatchToBackAnimation(ev);
}
}
-
- mProtoTracer.scheduleFrameUpdate();
}
private boolean isButtonPressFromTrackpad(MotionEvent ev) {
@@ -1285,14 +1273,6 @@
return topActivity != null && mGestureBlockingActivities.contains(topActivity);
}
- @Override
- public void writeToProto(SystemUiTraceProto proto) {
- if (proto.edgeBackGestureHandler == null) {
- proto.edgeBackGestureHandler = new EdgeBackGestureHandlerProto();
- }
- proto.edgeBackGestureHandler.allowGesture = mAllowGesture;
- }
-
public void setBackAnimation(BackAnimation backAnimation) {
mBackAnimation = backAnimation;
updateBackAnimationThresholds();
@@ -1319,7 +1299,6 @@
private final Handler mHandler;
private final Executor mBackgroundExecutor;
private final UserTracker mUserTracker;
- private final ProtoTracer mProtoTracer;
private final NavigationModeController mNavigationModeController;
private final BackPanelController.Factory mBackPanelControllerFactory;
private final ViewConfiguration mViewConfiguration;
@@ -1343,7 +1322,6 @@
@Main Handler handler,
@Background Executor backgroundExecutor,
UserTracker userTracker,
- ProtoTracer protoTracer,
NavigationModeController navigationModeController,
BackPanelController.Factory backPanelControllerFactory,
ViewConfiguration viewConfiguration,
@@ -1365,7 +1343,6 @@
mHandler = handler;
mBackgroundExecutor = backgroundExecutor;
mUserTracker = userTracker;
- mProtoTracer = protoTracer;
mNavigationModeController = navigationModeController;
mBackPanelControllerFactory = backPanelControllerFactory;
mViewConfiguration = viewConfiguration;
@@ -1392,7 +1369,6 @@
mHandler,
mBackgroundExecutor,
mUserTracker,
- mProtoTracer,
mNavigationModeController,
mBackPanelControllerFactory,
mViewConfiguration,
diff --git a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
index c13476f..eb1ca66 100644
--- a/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/domain/interactor/PowerInteractor.kt
@@ -20,6 +20,7 @@
import android.os.PowerManager
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.PowerRepository
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
@@ -32,6 +33,7 @@
@Inject
constructor(
private val repository: PowerRepository,
+ private val keyguardRepository: KeyguardRepository,
private val falsingCollector: FalsingCollector,
private val screenOffAnimationController: ScreenOffAnimationController,
private val statusBarStateController: StatusBarStateController,
@@ -54,4 +56,21 @@
falsingCollector.onScreenOnFromTouch()
}
}
+
+ /**
+ * Wakes up the device if the device was dozing or going to sleep in order to display a
+ * full-screen intent.
+ */
+ fun wakeUpForFullScreenIntent() {
+ if (
+ keyguardRepository.wakefulness.value.isStartingToSleep() ||
+ statusBarStateController.isDozing
+ ) {
+ repository.wakeUp(why = FSI_WAKE_WHY, wakeReason = PowerManager.WAKE_REASON_APPLICATION)
+ }
+ }
+
+ companion object {
+ private const val FSI_WAKE_WHY = "full_screen_intent"
+ }
}
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/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayEducationLottieViewWrapper.kt
similarity index 65%
copy from packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
copy to packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayEducationLottieViewWrapper.kt
index dd89441..716a4d6 100644
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayEducationLottieViewWrapper.kt
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.systemui.reardisplay
-/**
- * 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;
+import android.content.Context
+import android.util.AttributeSet
+import com.android.systemui.util.wrapper.LottieViewWrapper
+
+class RearDisplayEducationLottieViewWrapper
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index e7dde66..207cc139 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -25,11 +25,9 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
@@ -173,8 +171,6 @@
private boolean mInputFocusTransferStarted;
private float mInputFocusTransferStartY;
private long mInputFocusTransferStartMillis;
- private float mWindowCornerRadius;
- private boolean mSupportsRoundedCornersOnWindows;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
@VisibleForTesting
@@ -454,8 +450,6 @@
Bundle params = new Bundle();
params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
- params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
- params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
params.putBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER,
mSysuiUnlockAnimationController.asBinder());
mUnfoldTransitionProgressForwarder.ifPresent(
@@ -588,9 +582,6 @@
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
.setPackage(mRecentsComponentName.getPackageName());
- mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
- mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
- .supportsRoundedCornersOnWindows(mContext.getResources());
mSysUiState = sysUiState;
mSysUiState.addCallback(this::notifySystemUiStateFlags);
mUiEventLogger = uiEventLogger;
@@ -1084,8 +1075,6 @@
pw.print(" mInputFocusTransferStarted="); pw.println(mInputFocusTransferStarted);
pw.print(" mInputFocusTransferStartY="); pw.println(mInputFocusTransferStartY);
pw.print(" mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis);
- pw.print(" mWindowCornerRadius="); pw.println(mWindowCornerRadius);
- pw.print(" mSupportsRoundedCornersOnWindows="); pw.println(mSupportsRoundedCornersOnWindows);
pw.print(" mActiveNavBarRegion="); pw.println(mActiveNavBarRegion);
pw.print(" mNavigationBarSurface="); pw.println(mNavigationBarSurface);
pw.print(" mNavBarMode="); pw.println(mNavBarMode);
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..285ff74
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartable.kt
@@ -0,0 +1,134 @@
+/*
+ * 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.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.shared.model.WakefulnessState
+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 keyguardInteractor: KeyguardInteractor,
+ 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 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 -> switchToScene(targetSceneKey) }
+ }
+
+ applicationScope.launch {
+ keyguardInteractor.wakefulnessModel
+ .map { it.state == WakefulnessState.ASLEEP }
+ .distinctUntilChanged()
+ .collect { isAsleep ->
+ if (isAsleep) {
+ // When the device goes to sleep, reset the current scene.
+ val isUnlocked = authenticationInteractor.isUnlocked.value
+ switchToScene(if (isUnlocked) SceneKey.Gone else SceneKey.Lockscreen)
+ }
+ }
+ }
+ }
+
+ private fun switchToScene(targetSceneKey: SceneKey) {
+ sceneInteractor.setCurrentScene(
+ containerName = CONTAINER_NAME,
+ scene = SceneModel(targetSceneKey),
+ )
+ }
+
+ companion object {
+ private const val CONTAINER_NAME = SceneContainerNames.SYSTEM_UI_DEFAULT
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
similarity index 63%
copy from packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
copy to packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
index dd89441..c8f46a7 100644
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneTransitionModel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 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,10 +14,12 @@
* 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;
+package com.android.systemui.scene.shared.model
+
+/** 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/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
index a9cecaa..6f2256e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
@@ -117,18 +117,22 @@
@Override
protected Parcelable onSaveInstanceState() {
+ Log.d(TAG, "onSaveInstanceState");
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.mCrop = mCrop;
+ Log.d(TAG, "saving mCrop=" + mCrop);
+
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
+ Log.d(TAG, "onRestoreInstanceState");
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
-
+ Log.d(TAG, "restoring mCrop=" + ss.mCrop + " (was " + mCrop + ")");
mCrop = ss.mCrop;
}
@@ -242,6 +246,7 @@
* Set the given boundary to the given value without animation.
*/
public void setBoundaryPosition(CropBoundary boundary, float position) {
+ Log.i(TAG, "setBoundaryPosition: " + boundary + ", position=" + position);
position = (float) getAllowedValues(boundary).clamp(position);
switch (boundary) {
case TOP:
@@ -260,6 +265,7 @@
Log.w(TAG, "No boundary selected");
break;
}
+ Log.i(TAG, "Updated mCrop: " + mCrop);
invalidate();
}
@@ -350,26 +356,31 @@
mCropInteractionListener = listener;
}
- private Range getAllowedValues(CropBoundary boundary) {
+ private Range<Float> getAllowedValues(CropBoundary boundary) {
+ float upper = 0f;
+ float lower = 1f;
switch (boundary) {
case TOP:
- return new Range<>(0f,
- mCrop.bottom - pixelDistanceToFraction(mCropTouchMargin,
- CropBoundary.BOTTOM));
+ lower = 0f;
+ upper = mCrop.bottom - pixelDistanceToFraction(mCropTouchMargin,
+ CropBoundary.BOTTOM);
+ break;
case BOTTOM:
- return new Range<>(
- mCrop.top + pixelDistanceToFraction(mCropTouchMargin,
- CropBoundary.TOP), 1f);
+ lower = mCrop.top + pixelDistanceToFraction(mCropTouchMargin, CropBoundary.TOP);
+ upper = 1;
+ break;
case LEFT:
- return new Range<>(0f,
- mCrop.right - pixelDistanceToFraction(mCropTouchMargin,
- CropBoundary.RIGHT));
+ lower = 0f;
+ upper = mCrop.right - pixelDistanceToFraction(mCropTouchMargin, CropBoundary.RIGHT);
+ break;
case RIGHT:
- return new Range<>(
- mCrop.left + pixelDistanceToFraction(mCropTouchMargin,
- CropBoundary.LEFT), 1f);
+ lower = mCrop.left + pixelDistanceToFraction(mCropTouchMargin, CropBoundary.LEFT);
+ upper = 1;
+ break;
}
- return null;
+ Log.i(TAG, "getAllowedValues: " + boundary + ", "
+ + "result=[lower=" + lower + ", upper=" + upper + "]");
+ return new Range<>(lower, upper);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 4bc7ec8..e6e1fac 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -36,17 +36,18 @@
import android.util.Log;
import android.view.ScrollCaptureResponse;
import android.view.View;
-import android.view.ViewTreeObserver;
import android.widget.ImageView;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.internal.app.ChooserActivity;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.view.OneShotPreDrawListener;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.screenshot.CropView.CropBoundary;
import com.android.systemui.screenshot.ScrollCaptureController.LongScreenshot;
import com.android.systemui.settings.UserTracker;
@@ -215,6 +216,7 @@
mPreview.setImageDrawable(drawable);
mMagnifierView.setDrawable(mLongScreenshot.getDrawable(),
mLongScreenshot.getWidth(), mLongScreenshot.getHeight());
+ Log.i(TAG, "Completed: " + longScreenshot);
// Original boundaries go from the image tile set's y=0 to y=pageSize, so
// we animate to that as a starting crop position.
float topFraction = Math.max(0,
@@ -223,31 +225,26 @@
1 - (mLongScreenshot.getBottom() - mLongScreenshot.getPageHeight())
/ (float) mLongScreenshot.getHeight());
+ Log.i(TAG, "topFraction: " + topFraction);
+ Log.i(TAG, "bottomFraction: " + bottomFraction);
+
mEnterTransitionView.setImageDrawable(drawable);
- mEnterTransitionView.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- mEnterTransitionView.getViewTreeObserver().removeOnPreDrawListener(this);
- updateImageDimensions();
- mEnterTransitionView.post(() -> {
- Rect dest = new Rect();
- mEnterTransitionView.getBoundsOnScreen(dest);
- mLongScreenshotHolder.takeTransitionDestinationCallback()
- .setTransitionDestination(dest, () -> {
- mPreview.animate().alpha(1f);
- mCropView.setBoundaryPosition(
- CropView.CropBoundary.TOP, topFraction);
- mCropView.setBoundaryPosition(
- CropView.CropBoundary.BOTTOM, bottomFraction);
- mCropView.animateEntrance();
- mCropView.setVisibility(View.VISIBLE);
- setButtonsEnabled(true);
- });
+ OneShotPreDrawListener.add(mEnterTransitionView, () -> {
+ updateImageDimensions();
+ mEnterTransitionView.post(() -> {
+ Rect dest = new Rect();
+ mEnterTransitionView.getBoundsOnScreen(dest);
+ mLongScreenshotHolder.takeTransitionDestinationCallback()
+ .setTransitionDestination(dest, () -> {
+ mPreview.animate().alpha(1f);
+ mCropView.setBoundaryPosition(CropBoundary.TOP, topFraction);
+ mCropView.setBoundaryPosition(CropBoundary.BOTTOM, bottomFraction);
+ mCropView.animateEntrance();
+ mCropView.setVisibility(View.VISIBLE);
+ setButtonsEnabled(true);
});
- return true;
- }
- });
+ });
+ });
// Immediately export to temp image file for saved state
mCacheSaveFuture = mImageExporter.exportToRawFile(mBackgroundExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 30a0b8f..bb34ede 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -130,8 +130,14 @@
@Override
public String toString() {
- return "LongScreenshot{w=" + mImageTileSet.getWidth()
- + ", h=" + mImageTileSet.getHeight() + "}";
+ return "LongScreenshot{"
+ + "l=" + mImageTileSet.getLeft() + ", "
+ + "t=" + mImageTileSet.getTop() + ", "
+ + "r=" + mImageTileSet.getRight() + ", "
+ + "b=" + mImageTileSet.getBottom() + ", "
+ + "w=" + mImageTileSet.getWidth() + ", "
+ + "h=" + mImageTileSet.getHeight()
+ + "}";
}
public Drawable getDrawable() {
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 5199bd4..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;
}
@@ -122,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);
@@ -139,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/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index d97db3b..ea15035 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1076,6 +1076,8 @@
mTapAgainViewController.init();
mShadeHeaderController.init();
+ mShadeHeaderController.setShadeCollapseAction(
+ () -> collapse(/* delayed= */ false , /* speedUpFactor= */ 1.0f));
mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
mNotificationPanelUnfoldAnimationController.ifPresent(controller ->
controller.setup(mNotificationContainerParent));
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 8105a145..481da52 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..5f95bca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.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..8b89ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -122,6 +122,8 @@
}
}
+ var shadeCollapseAction: Runnable? = null
+
private lateinit var iconManager: StatusBarIconController.TintedIconManager
private lateinit var carrierIconSlots: List<String>
private lateinit var mShadeCarrierGroupController: ShadeCarrierGroupController
@@ -131,6 +133,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 +257,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 +277,7 @@
lastInsets?.let { updateConstraintsForInsets(header, it) }
updateResources()
updateCarrierGroupPadding()
+ clock.onDensityOrFontScaleChanged()
}
}
@@ -459,9 +471,11 @@
if (largeScreenActive) {
logInstantEvent("Large screen constraints set")
header.setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID)
+ systemIcons.setOnClickListener { shadeCollapseAction?.run() }
} else {
logInstantEvent("Small screen constraints set")
header.setTransition(HEADER_TRANSITION_ID)
+ systemIcons.setOnClickListener(null)
}
header.jumpToState(header.startState)
updatePosition()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 8ae9e5e..8ec8d11 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -50,6 +50,7 @@
import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.phone.KeyguardBottomAreaView
+import com.android.systemui.statusbar.phone.StatusBarLocation
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.phone.TapAgainView
import com.android.systemui.statusbar.policy.BatteryController
@@ -64,7 +65,7 @@
import javax.inject.Provider
/** Module for classes related to the notification shade. */
-@Module
+@Module(includes = [StartShadeModule::class])
abstract class ShadeModule {
@Binds
@@ -281,17 +282,16 @@
tunerService: TunerService,
@Main mainHandler: Handler,
contentResolver: ContentResolver,
- featureFlags: FeatureFlags,
batteryController: BatteryController,
): BatteryMeterViewController {
return BatteryMeterViewController(
batteryMeterView,
+ StatusBarLocation.QS,
userTracker,
configurationController,
tunerService,
mainHandler,
contentResolver,
- featureFlags,
batteryController,
)
}
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/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java b/packages/SystemUI/src/com/android/systemui/shade/StartShadeModule.kt
similarity index 61%
copy from packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
copy to packages/SystemUI/src/com/android/systemui/shade/StartShadeModule.kt
index dd89441..c50693c 100644
--- a/packages/SettingsLib/tests/robotests/fragment/src/main/java/org/robolectric/shadows/androidx/fragment/package-info.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/StartShadeModule.kt
@@ -14,10 +14,18 @@
* 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;
+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/BaseStatusBarFrameLayout.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarFrameLayout.kt
index ce730ba..5d06f8d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarFrameLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarFrameLayout.kt
@@ -21,8 +21,8 @@
/**
* A temporary base class that's shared between our old status bar connectivity view implementations
- * ([StatusBarWifiView], [StatusBarMobileView]) and our new status bar implementations (
- * [ModernStatusBarWifiView], [ModernStatusBarMobileView]).
+ * ([StatusBarMobileView]) and our new status bar implementations ([ModernStatusBarWifiView],
+ * [ModernStatusBarMobileView]).
*
* Once our refactor is over, we should be able to delete this go-between class and the old view
* class.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index a532195..92df78b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -73,7 +73,6 @@
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.statusbar.policy.CallbackController;
-import com.android.systemui.tracing.ProtoTracer;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
@@ -190,7 +189,6 @@
*/
private int mLastUpdatedImeDisplayId = INVALID_DISPLAY;
private final DisplayTracker mDisplayTracker;
- private ProtoTracer mProtoTracer;
private final @Nullable CommandRegistry mRegistry;
private final @Nullable DumpHandler mDumpHandler;
@@ -504,18 +502,16 @@
@VisibleForTesting
public CommandQueue(Context context, DisplayTracker displayTracker) {
- this(context, displayTracker, null, null, null);
+ this(context, displayTracker, null, null);
}
public CommandQueue(
Context context,
DisplayTracker displayTracker,
- ProtoTracer protoTracer,
CommandRegistry registry,
DumpHandler dumpHandler
) {
mDisplayTracker = displayTracker;
- mProtoTracer = protoTracer;
mRegistry = registry;
mDumpHandler = dumpHandler;
mDisplayTracker.addDisplayChangeCallback(new DisplayTracker.Callback() {
@@ -1160,9 +1156,6 @@
@Override
public void startTracing() {
synchronized (mLock) {
- if (mProtoTracer != null) {
- mProtoTracer.start();
- }
mHandler.obtainMessage(MSG_TRACING_STATE_CHANGED, true).sendToTarget();
}
}
@@ -1170,9 +1163,6 @@
@Override
public void stopTracing() {
synchronized (mLock) {
- if (mProtoTracer != null) {
- mProtoTracer.stop();
- }
mHandler.obtainMessage(MSG_TRACING_STATE_CHANGED, false).sendToTarget();
}
}
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/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 91c08a0..fbbee53 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);
@@ -156,7 +160,6 @@
private ObjectAnimator mIconAppearAnimator;
private ObjectAnimator mDotAnimator;
private float mDotAppearAmount;
- private OnVisibilityChangedListener mOnVisibilityChangedListener;
private int mDrawableColor;
private int mIconColor;
private int mDecorColor;
@@ -175,7 +178,6 @@
private int mCachedContrastBackgroundColor = NO_COLOR;
private float[] mMatrix;
private ColorMatrixColorFilter mMatrixColorFilter;
- private boolean mIsInShelf;
private Runnable mLayoutRunnable;
private boolean mDismissed;
private Runnable mOnDismissListener;
@@ -198,30 +200,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 +221,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 +300,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 +313,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,17 +351,8 @@
maybeUpdateIconScaleDimens();
}
- private static boolean streq(String a, String b) {
- if (a == b) {
- return true;
- }
- if (a == null && b != null) {
- return false;
- }
- if (a != null && b == null) {
- return false;
- }
- return a.equals(b);
+ private boolean isNotification() {
+ return mNotification != null;
}
public boolean equalIcons(Icon a, Icon b) {
@@ -416,7 +449,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 +504,7 @@
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
- if (mNotification != null) {
+ if (isNotification()) {
event.setParcelableData(mNotification.getNotification());
}
}
@@ -491,11 +524,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 +563,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 +680,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));
@@ -837,7 +893,7 @@
if (targetAmount != currentAmount) {
mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
currentAmount, targetAmount);
- mDotAnimator.setInterpolator(interpolator);;
+ mDotAnimator.setInterpolator(interpolator);
mDotAnimator.setDuration(duration == 0 ? ANIMATION_DURATION_FAST
: duration);
final boolean runRunnable = !runnableAdded;
@@ -894,22 +950,10 @@
}
}
- @Override
- public void setVisibility(int visibility) {
- super.setVisibility(visibility);
- if (mOnVisibilityChangedListener != null) {
- mOnVisibilityChangedListener.onVisibilityChanged(visibility);
- }
- }
-
public float getDotAppearAmount() {
return mDotAppearAmount;
}
- public void setOnVisibilityChangedListener(OnVisibilityChangedListener listener) {
- mOnVisibilityChangedListener = listener;
- }
-
public void setDozing(boolean dozing, boolean fade, long delay) {
mDozer.setDozing(f -> {
mDozeAmount = f;
@@ -943,14 +987,6 @@
outRect.bottom += translationY;
}
- public void setIsInShelf(boolean isInShelf) {
- mIsInShelf = isInShelf;
- }
-
- public boolean isInShelf() {
- return mIsInShelf;
- }
-
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -1032,8 +1068,4 @@
public boolean showsConversation() {
return mShowsConversation;
}
-
- public interface OnVisibilityChangedListener {
- void onVisibilityChanged(int newVisibility);
- }
}
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
deleted file mode 100644
index decc70d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import static com.android.systemui.plugins.DarkIconDispatcher.getTint;
-import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
-import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
-import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-
-import java.util.ArrayList;
-
-/**
- * Start small: StatusBarWifiView will be able to layout from a WifiIconState
- */
-public class StatusBarWifiView extends BaseStatusBarFrameLayout implements DarkReceiver {
- private static final String TAG = "StatusBarWifiView";
-
- /// Used to show etc dots
- private StatusBarIconView mDotView;
- /// Contains the main icon layout
- private LinearLayout mWifiGroup;
- private ImageView mWifiIcon;
- private ImageView mIn;
- private ImageView mOut;
- private View mInoutContainer;
- private View mSignalSpacer;
- private View mAirplaneSpacer;
- private WifiIconState mState;
- private String mSlot;
- @StatusBarIconView.VisibleState
- private int mVisibleState = STATE_HIDDEN;
-
- public static StatusBarWifiView fromContext(Context context, String slot) {
- LayoutInflater inflater = LayoutInflater.from(context);
- StatusBarWifiView v = (StatusBarWifiView) inflater.inflate(R.layout.status_bar_wifi_group, null);
- v.setSlot(slot);
- v.init();
- v.setVisibleState(STATE_ICON);
- return v;
- }
-
- public StatusBarWifiView(Context context) {
- super(context);
- }
-
- public StatusBarWifiView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public StatusBarWifiView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public void setSlot(String slot) {
- mSlot = slot;
- }
-
- @Override
- public void setStaticDrawableColor(int color) {
- ColorStateList list = ColorStateList.valueOf(color);
- mWifiIcon.setImageTintList(list);
- mIn.setImageTintList(list);
- mOut.setImageTintList(list);
- mDotView.setDecorColor(color);
- }
-
- @Override
- public void setDecorColor(int color) {
- mDotView.setDecorColor(color);
- }
-
- @Override
- public String getSlot() {
- return mSlot;
- }
-
- @Override
- public boolean isIconVisible() {
- return mState != null && mState.visible;
- }
-
- @Override
- public void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate) {
- if (state == mVisibleState) {
- return;
- }
- mVisibleState = state;
-
- switch (state) {
- case STATE_ICON:
- mWifiGroup.setVisibility(View.VISIBLE);
- mDotView.setVisibility(View.GONE);
- break;
- case STATE_DOT:
- mWifiGroup.setVisibility(View.GONE);
- mDotView.setVisibility(View.VISIBLE);
- break;
- case STATE_HIDDEN:
- default:
- mWifiGroup.setVisibility(View.GONE);
- mDotView.setVisibility(View.GONE);
- break;
- }
- }
-
- @Override
- @StatusBarIconView.VisibleState
- public int getVisibleState() {
- return mVisibleState;
- }
-
- @Override
- public void getDrawingRect(Rect outRect) {
- super.getDrawingRect(outRect);
- float translationX = getTranslationX();
- float translationY = getTranslationY();
- outRect.left += translationX;
- outRect.right += translationX;
- outRect.top += translationY;
- outRect.bottom += translationY;
- }
-
- private void init() {
- mWifiGroup = findViewById(R.id.wifi_group);
- mWifiIcon = findViewById(R.id.wifi_signal);
- mIn = findViewById(R.id.wifi_in);
- mOut = findViewById(R.id.wifi_out);
- mSignalSpacer = findViewById(R.id.wifi_signal_spacer);
- mAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer);
- mInoutContainer = findViewById(R.id.inout_container);
-
- initDotView();
- }
-
- private void initDotView() {
- mDotView = new StatusBarIconView(mContext, mSlot, null);
- mDotView.setVisibleState(STATE_DOT);
-
- int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size);
- LayoutParams lp = new LayoutParams(width, width);
- lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
- addView(mDotView, lp);
- }
-
- public void applyWifiState(WifiIconState state) {
- boolean requestLayout = false;
-
- if (state == null) {
- requestLayout = getVisibility() != View.GONE;
- setVisibility(View.GONE);
- mState = null;
- } else if (mState == null) {
- requestLayout = true;
- mState = state.copy();
- initViewState();
- } else if (!mState.equals(state)) {
- requestLayout = updateState(state.copy());
- }
-
- if (requestLayout) {
- requestLayout();
- }
- }
-
- private boolean updateState(WifiIconState state) {
- setContentDescription(state.contentDescription);
- if (mState.resId != state.resId && state.resId >= 0) {
- mWifiIcon.setImageDrawable(mContext.getDrawable(state.resId));
- }
-
- mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
- mOut.setVisibility(state.activityOut ? View.VISIBLE : View.GONE);
- mInoutContainer.setVisibility(
- (state.activityIn || state.activityOut) ? View.VISIBLE : View.GONE);
- mAirplaneSpacer.setVisibility(state.airplaneSpacerVisible ? View.VISIBLE : View.GONE);
- mSignalSpacer.setVisibility(state.signalSpacerVisible ? View.VISIBLE : View.GONE);
-
- boolean needsLayout = state.activityIn != mState.activityIn
- ||state.activityOut != mState.activityOut;
-
- if (mState.visible != state.visible) {
- needsLayout |= true;
- setVisibility(state.visible ? View.VISIBLE : View.GONE);
- }
-
- mState = state;
- return needsLayout;
- }
-
- private void initViewState() {
- setContentDescription(mState.contentDescription);
- if (mState.resId >= 0) {
- mWifiIcon.setImageDrawable(mContext.getDrawable(mState.resId));
- }
-
- mIn.setVisibility(mState.activityIn ? View.VISIBLE : View.GONE);
- mOut.setVisibility(mState.activityOut ? View.VISIBLE : View.GONE);
- mInoutContainer.setVisibility(
- (mState.activityIn || mState.activityOut) ? View.VISIBLE : View.GONE);
- mAirplaneSpacer.setVisibility(mState.airplaneSpacerVisible ? View.VISIBLE : View.GONE);
- mSignalSpacer.setVisibility(mState.signalSpacerVisible ? View.VISIBLE : View.GONE);
- setVisibility(mState.visible ? View.VISIBLE : View.GONE);
- }
-
- @Override
- public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
- int areaTint = getTint(areas, this, tint);
- ColorStateList color = ColorStateList.valueOf(areaTint);
- mWifiIcon.setImageTintList(color);
- mIn.setImageTintList(color);
- mOut.setImageTintList(color);
- mDotView.setDecorColor(areaTint);
- mDotView.setIconColor(areaTint, false);
- }
-
-
- @Override
- public String toString() {
- return "StatusBarWifiView(slot=" + mSlot + " state=" + mState + ")";
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 73f181b..9aa28c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -18,10 +18,6 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN;
-import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT;
-import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
-import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import android.annotation.Nullable;
@@ -557,10 +553,6 @@
mBroadcastDispatcher.unregisterReceiver(this);
}
- public int getConnectedWifiLevel() {
- return mWifiSignalController.getState().level;
- }
-
@Override
public AccessPointController getAccessPointController() {
return mAccessPoints;
@@ -654,14 +646,6 @@
return mWifiSignalController.isCarrierMergedWifi(subId);
}
- boolean hasDefaultNetwork() {
- return !mNoDefaultNetwork;
- }
-
- boolean isNonCarrierWifiNetworkAvailable() {
- return !mNoNetworksAvailable;
- }
-
boolean isEthernetDefault() {
return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
}
@@ -1242,15 +1226,12 @@
}
private boolean mDemoInetCondition;
- private WifiState mDemoWifiState;
@Override
public void onDemoModeStarted() {
if (DEBUG) Log.d(TAG, "Entering demo mode");
unregisterListeners();
mDemoInetCondition = mInetCondition;
- mDemoWifiState = mWifiSignalController.getState();
- mDemoWifiState.ssid = "DemoMode";
}
@Override
@@ -1300,41 +1281,6 @@
controller.updateConnectivity(connected, connected);
}
}
- String wifi = args.getString("wifi");
- if (wifi != null && !mStatusBarPipelineFlags.runNewWifiIconBackend()) {
- boolean show = wifi.equals("show");
- String level = args.getString("level");
- if (level != null) {
- mDemoWifiState.level = level.equals("null") ? -1
- : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
- mDemoWifiState.connected = mDemoWifiState.level >= 0;
- }
- String activity = args.getString("activity");
- if (activity != null) {
- switch (activity) {
- case "inout":
- mWifiSignalController.setActivity(DATA_ACTIVITY_INOUT);
- break;
- case "in":
- mWifiSignalController.setActivity(DATA_ACTIVITY_IN);
- break;
- case "out":
- mWifiSignalController.setActivity(DATA_ACTIVITY_OUT);
- break;
- default:
- mWifiSignalController.setActivity(DATA_ACTIVITY_NONE);
- break;
- }
- } else {
- mWifiSignalController.setActivity(DATA_ACTIVITY_NONE);
- }
- String ssid = args.getString("ssid");
- if (ssid != null) {
- mDemoWifiState.ssid = ssid;
- }
- mDemoWifiState.enabled = show;
- mWifiSignalController.notifyListeners();
- }
String sims = args.getString("sims");
if (sims != null && !mStatusBarPipelineFlags.useNewMobileIcons()) {
int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 035fa04..e5ba3ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -78,7 +78,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
-import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
@@ -195,11 +194,10 @@
static CommandQueue provideCommandQueue(
Context context,
DisplayTracker displayTracker,
- ProtoTracer protoTracer,
CommandRegistry registry,
DumpHandler dumpHandler
) {
- return new CommandQueue(context, displayTracker, protoTracer, registry, dumpHandler);
+ return new CommandQueue(context, displayTracker, registry, dumpHandler);
}
/**
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/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
index 5f28ecb..577ad20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
@@ -16,27 +16,21 @@
package com.android.systemui.statusbar.notification
-import android.content.Context
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.FlagResolver
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import javax.inject.Inject
-class NotifPipelineFlags @Inject constructor(
- val context: Context,
- val featureFlags: FeatureFlags,
- val sysPropFlags: FlagResolver,
+class NotifPipelineFlags
+@Inject
+constructor(
+ private val featureFlags: FeatureFlags,
+ private val sysPropFlags: FlagResolver,
) {
fun isDevLoggingEnabled(): Boolean =
featureFlags.isEnabled(Flags.NOTIFICATION_PIPELINE_DEVELOPER_LOGGING)
fun allowDismissOngoing(): Boolean =
- sysPropFlags.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)
-
- fun isOtpRedactionEnabled(): Boolean =
- sysPropFlags.isEnabled(NotificationFlags.OTP_REDACTION)
-
- val isNoHunForOldWhenEnabled: Boolean
- get() = featureFlags.isEnabled(Flags.NO_HUN_FOR_OLD_WHEN)
+ sysPropFlags.isEnabled(NotificationFlags.ALLOW_DISMISS_ONGOING)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
index 212f2c215..1cf9c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
@@ -3,7 +3,10 @@
import android.util.FloatProperty
import android.view.View
import androidx.annotation.FloatRange
+import com.android.systemui.Dependency
import com.android.systemui.R
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.notification.stack.AnimationProperties
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import kotlin.math.abs
@@ -20,6 +23,8 @@
/** Properties required for a Roundable */
val roundableState: RoundableState
+ val clipHeight: Int
+
/** Current top roundness */
@get:FloatRange(from = 0.0, to = 1.0)
@JvmDefault
@@ -40,12 +45,16 @@
/** Current top corner in pixel, based on [topRoundness] and [maxRadius] */
@JvmDefault
val topCornerRadius: Float
- get() = topRoundness * maxRadius
+ get() =
+ if (roundableState.newHeadsUpAnimFlagEnabled) roundableState.topCornerRadius
+ else topRoundness * maxRadius
/** Current bottom corner in pixel, based on [bottomRoundness] and [maxRadius] */
@JvmDefault
val bottomCornerRadius: Float
- get() = bottomRoundness * maxRadius
+ get() =
+ if (roundableState.newHeadsUpAnimFlagEnabled) roundableState.bottomCornerRadius
+ else bottomRoundness * maxRadius
/** Get and update the current radii */
@JvmDefault
@@ -320,14 +329,20 @@
* @param roundable Target of the radius animation
* @param maxRadius Max corner radius in pixels
*/
-class RoundableState(
+class RoundableState
+@JvmOverloads
+constructor(
internal val targetView: View,
private val roundable: Roundable,
maxRadius: Float,
+ private val featureFlags: FeatureFlags = Dependency.get(FeatureFlags::class.java)
) {
internal var maxRadius = maxRadius
private set
+ internal val newHeadsUpAnimFlagEnabled
+ get() = featureFlags.isEnabled(Flags.IMPROVED_HUN_ANIMATIONS)
+
/** Animatable for top roundness */
private val topAnimatable = topAnimatable(roundable)
@@ -344,6 +359,41 @@
internal var bottomRoundness = 0f
private set
+ internal val topCornerRadius: Float
+ get() {
+ val height = roundable.clipHeight
+ val topRadius = topRoundness * maxRadius
+ val bottomRadius = bottomRoundness * maxRadius
+
+ if (height == 0) {
+ return 0f
+ } else if (topRadius + bottomRadius > height) {
+ // The sum of top and bottom corner radii should be at max the clipped height
+ val overShoot = topRadius + bottomRadius - height
+ return topRadius - (overShoot * topRoundness / (topRoundness + bottomRoundness))
+ }
+
+ return topRadius
+ }
+
+ internal val bottomCornerRadius: Float
+ get() {
+ val height = roundable.clipHeight
+ val topRadius = topRoundness * maxRadius
+ val bottomRadius = bottomRoundness * maxRadius
+
+ if (height == 0) {
+ return 0f
+ } else if (topRadius + bottomRadius > height) {
+ // The sum of top and bottom corner radii should be at max the clipped height
+ val overShoot = topRadius + bottomRadius - height
+ return bottomRadius -
+ (overShoot * bottomRoundness / (topRoundness + bottomRoundness))
+ }
+
+ return bottomRadius
+ }
+
/** Last requested top roundness associated by [SourceType] */
internal val topRoundnessMap = mutableMapOf<SourceType, Float>()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 609f9d4..0c43da0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -582,10 +582,6 @@
}
private boolean shouldSuppressHeadsUpWhenAwakeForOldWhen(NotificationEntry entry, boolean log) {
- if (!mFlags.isNoHunForOldWhenEnabled()) {
- return false;
- }
-
final Notification notification = entry.getSbn().getNotification();
if (notification == null) {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 27510d4..908c11a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -566,12 +566,20 @@
@Override
public float getTopCornerRadius() {
+ if (isNewHeadsUpAnimFlagEnabled()) {
+ return super.getTopCornerRadius();
+ }
+
float fraction = getInterpolatedAppearAnimationFraction();
return MathUtils.lerp(0, super.getTopCornerRadius(), fraction);
}
@Override
public float getBottomCornerRadius() {
+ if (isNewHeadsUpAnimFlagEnabled()) {
+ return super.getBottomCornerRadius();
+ }
+
float fraction = getInterpolatedAppearAnimationFraction();
return MathUtils.lerp(0, super.getBottomCornerRadius(), fraction);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index 9aa50e9..7f23c1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -28,7 +28,10 @@
import android.view.View;
import android.view.ViewOutlineProvider;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.statusbar.notification.RoundableState;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import com.android.systemui.util.DumpUtilsKt;
@@ -47,12 +50,14 @@
private float mOutlineAlpha = -1f;
private boolean mAlwaysRoundBothCorners;
private Path mTmpPath = new Path();
+ private final FeatureFlags mFeatureFlags;
/**
* {@code false} if the children views of the {@link ExpandableOutlineView} are translated when
* it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself.
*/
protected boolean mDismissUsingRowTranslationX = true;
+
private float[] mTmpCornerRadii = new float[8];
private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@@ -81,6 +86,15 @@
return mRoundableState;
}
+ @Override
+ public int getClipHeight() {
+ if (mCustomOutline) {
+ return mOutlineRect.height();
+ }
+
+ return super.getClipHeight();
+ }
+
protected Path getClipPath(boolean ignoreTranslation) {
int left;
int top;
@@ -112,7 +126,7 @@
return EMPTY_PATH;
}
float bottomRadius = mAlwaysRoundBothCorners ? getMaxRadius() : getBottomCornerRadius();
- if (topRadius + bottomRadius > height) {
+ if (!isNewHeadsUpAnimFlagEnabled() && (topRadius + bottomRadius > height)) {
float overShoot = topRadius + bottomRadius - height;
float currentTopRoundness = getTopRoundness();
float currentBottomRoundness = getBottomRoundness();
@@ -153,6 +167,7 @@
super(context, attrs);
setOutlineProvider(mProvider);
initDimens();
+ mFeatureFlags = Dependency.get(FeatureFlags.class);
}
@Override
@@ -360,4 +375,9 @@
}
});
}
+
+ // TODO(b/290365128) replace with ViewRefactorFlag
+ protected boolean isNewHeadsUpAnimFlagEnabled() {
+ return mFeatureFlags.isEnabled(Flags.IMPROVED_HUN_ANIMATIONS);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index f986244..c4c116b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -93,6 +93,12 @@
return mRoundableState;
}
+ @Override
+ public int getClipHeight() {
+ int clipHeight = Math.max(mActualHeight - mClipTopAmount - mClipBottomAmount, 0);
+ return Math.max(clipHeight, mMinimumHeightForClipping);
+ }
+
private void initDimens() {
mContentShift = getResources().getDimensionPixelSize(
R.dimen.shelf_transform_content_shift);
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/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index ef5e86f06..87205e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -120,6 +120,11 @@
}
@Override
+ public int getClipHeight() {
+ return mView.getHeight();
+ }
+
+ @Override
public void applyRoundnessAndInvalidate() {
if (mRoundnessChangedListener != null) {
// We cannot apply the rounded corner to this View, so our parents (in drawChild()) will
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
index 04308b4..a8d8a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
@@ -30,8 +30,8 @@
*/
class MediaContainerView(context: Context, attrs: AttributeSet?) : ExpandableView(context, attrs) {
+ override var clipHeight = 0
var cornerRadius = 0f
- var clipHeight = 0
var clipRect = RectF()
var clipPath = Path()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index dad8064..626f851 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -192,6 +192,11 @@
}
@Override
+ public int getClipHeight() {
+ return Math.max(mActualHeight - mClipBottomAmount, 0);
+ }
+
+ @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount =
Math.min(mAttachedChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
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..c1ceb3c 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
@@ -3758,20 +3758,20 @@
case MotionEvent.ACTION_UP:
if (mStatusBarState != StatusBarState.KEYGUARD && mTouchIsClick &&
isBelowLastNotification(mInitialTouchX, mInitialTouchY)) {
- debugLog("handleEmptySpaceClick: touch event propagated further");
+ debugShadeLog("handleEmptySpaceClick: touch event propagated further");
mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
}
break;
default:
- debugLog("handleEmptySpaceClick: MotionEvent ignored");
+ debugShadeLog("handleEmptySpaceClick: MotionEvent ignored");
}
}
- private void debugLog(@CompileTimeConstant final String s) {
+ private void debugShadeLog(@CompileTimeConstant final String s) {
if (mLogger == null) {
return;
}
- mLogger.d(s);
+ mLogger.logShadeDebugEvent(s);
}
private void logEmptySpaceClick(MotionEvent ev, boolean isTouchBelowLastNotification,
@@ -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/notification/stack/NotificationStackScrollLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
index 2c38b8d..3396306 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
@@ -7,6 +7,7 @@
import com.android.systemui.log.core.LogLevel.ERROR
import com.android.systemui.log.dagger.NotificationHeadsUpLog
import com.android.systemui.log.dagger.NotificationRenderLog
+import com.android.systemui.log.dagger.ShadeLog
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.logKey
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD
@@ -19,7 +20,8 @@
class NotificationStackScrollLogger @Inject constructor(
@NotificationHeadsUpLog private val buffer: LogBuffer,
- @NotificationRenderLog private val notificationRenderBuffer: LogBuffer
+ @NotificationRenderLog private val notificationRenderBuffer: LogBuffer,
+ @ShadeLog private val shadeLogBuffer: LogBuffer,
) {
fun hunAnimationSkipped(entry: NotificationEntry, reason: String) {
buffer.log(TAG, INFO, {
@@ -63,7 +65,7 @@
})
}
- fun d(@CompileTimeConstant msg: String) = buffer.log(TAG, DEBUG, msg)
+ fun logShadeDebugEvent(@CompileTimeConstant msg: String) = shadeLogBuffer.log(TAG, DEBUG, msg)
fun logEmptySpaceClick(
isBelowLastNotification: Boolean,
@@ -71,7 +73,7 @@
touchIsClick: Boolean,
motionEventDesc: String
) {
- buffer.log(TAG, DEBUG, {
+ shadeLogBuffer.log(TAG, DEBUG, {
int1 = statusBarState
bool1 = touchIsClick
bool2 = isBelowLastNotification
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index 730ef57..26b51a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -37,6 +37,7 @@
import com.android.systemui.assist.AssistManager
import com.android.systemui.camera.CameraIntents.Companion.isInsecureCameraIntent
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.DisplayId
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
@@ -72,6 +73,7 @@
private val notifShadeWindowControllerLazy: Lazy<NotificationShadeWindowController>,
private val activityLaunchAnimator: ActivityLaunchAnimator,
private val context: Context,
+ @DisplayId private val displayId: Int,
private val lockScreenUserManager: NotificationLockscreenUserManager,
private val statusBarWindowController: StatusBarWindowController,
private val wakefulnessLifecycle: WakefulnessLifecycle,
@@ -471,9 +473,7 @@
intent.getPackage()
) { adapter: RemoteAnimationAdapter? ->
val options =
- ActivityOptions(
- CentralSurfaces.getActivityOptions(centralSurfaces!!.displayId, adapter)
- )
+ ActivityOptions(CentralSurfaces.getActivityOptions(displayId, adapter))
// We know that the intent of the caller is to dismiss the keyguard and
// this runnable is called right after the keyguard is solved, so we tell
@@ -596,7 +596,7 @@
val options =
ActivityOptions(
CentralSurfaces.getActivityOptions(
- centralSurfaces!!.displayId,
+ displayId,
animationAdapter
)
)
@@ -762,7 +762,7 @@
TaskStackBuilder.create(context)
.addNextIntent(intent)
.startActivities(
- CentralSurfaces.getActivityOptions(centralSurfaces!!.displayId, adapter),
+ CentralSurfaces.getActivityOptions(displayId, adapter),
userHandle
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 478baf2f..2b9c3d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -355,15 +355,11 @@
void updateNotificationPanelTouchState();
- int getDisplayId();
-
int getRotation();
@VisibleForTesting
void setBarStateForTest(int state);
- void wakeUpForFullScreenIntent();
-
void showTransientUnchecked();
void clearTransient();
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 8902a18..62e98f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -1613,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 +1772,7 @@
try {
EventLog.writeEvent(EventLogTags.SYSUI_HEADS_UP_ESCALATION,
sbn.getKey());
- wakeUpForFullScreenIntent();
+ mPowerInteractor.wakeUpForFullScreenIntent();
ActivityOptions opts = ActivityOptions.makeBasic();
opts.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
@@ -1786,16 +1785,6 @@
mHeadsUpManager.releaseAllImmediately();
}
- @Override
- public void wakeUpForFullScreenIntent() {
- if (isGoingToSleep() || mDozing) {
- mPowerManager.wakeUp(
- SystemClock.uptimeMillis(),
- PowerManager.WAKE_REASON_APPLICATION,
- "com.android.systemui:full_screen_intent");
- }
- }
-
/**
* Called when another window is about to transfer it's input focus.
*/
@@ -2108,11 +2097,6 @@
}
@Override
- public int getDisplayId() {
- return mDisplayId;
- }
-
- @Override
public void readyForKeyguardDone() {
mStatusBarKeyguardViewManager.readyForKeyguardDone();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 39b5b5a..8e9f382 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -35,11 +35,9 @@
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
-import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
@@ -58,7 +56,6 @@
private final ArrayList<ModernStatusBarMobileView> mModernMobileViews = new ArrayList<>();
private final int mIconSize;
- private StatusBarWifiView mWifiView;
private ModernStatusBarWifiView mModernWifiView;
private boolean mDemoMode;
private int mColor;
@@ -238,36 +235,6 @@
addView(v, 0, createLayoutParams());
}
- public void addDemoWifiView(WifiIconState state) {
- Log.d(TAG, "addDemoWifiView: ");
- StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, state.slot);
-
- int viewIndex = getChildCount();
- // If we have mobile views, put wifi before them
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (child instanceof StatusBarMobileView
- || child instanceof ModernStatusBarMobileView) {
- viewIndex = i;
- break;
- }
- }
-
- mWifiView = view;
- mWifiView.applyWifiState(state);
- mWifiView.setStaticDrawableColor(mColor);
- addView(view, viewIndex, createLayoutParams());
- }
-
- public void updateWifiState(WifiIconState state) {
- Log.d(TAG, "updateWifiState: ");
- if (mWifiView == null) {
- addDemoWifiView(state);
- } else {
- mWifiView.applyWifiState(state);
- }
- }
-
/**
* Add a new mobile icon view
*/
@@ -352,10 +319,7 @@
public void onRemoveIcon(StatusIconDisplayable view) {
if (view.getSlot().equals("wifi")) {
- if (view instanceof StatusBarWifiView) {
- removeView(mWifiView);
- mWifiView = null;
- } else if (view instanceof ModernStatusBarWifiView) {
+ if (view instanceof ModernStatusBarWifiView) {
Log.d(TAG, "onRemoveIcon: removing modern wifi view");
removeView(mModernWifiView);
mModernWifiView = null;
@@ -409,9 +373,6 @@
public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
setColor(DarkIconDispatcher.getTint(areas, mStatusIcons, tint));
- if (mWifiView != null) {
- mWifiView.onDarkChanged(areas, darkIntensity, tint);
- }
if (mModernWifiView != null) {
mModernWifiView.onDarkChanged(areas, darkIntensity, tint);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index f26a84b..dc5eb0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -38,8 +38,6 @@
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.settings.DisplayTracker;
@@ -65,7 +63,6 @@
private final SysuiDarkIconDispatcher mStatusBarIconController;
private final BatteryController mBatteryController;
- private final boolean mUseNewLightBarLogic;
private BiometricUnlockController mBiometricUnlockController;
private LightBarTransitionsController mNavigationBarController;
@@ -123,10 +120,8 @@
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
- FeatureFlags featureFlags,
DumpManager dumpManager,
DisplayTracker displayTracker) {
- mUseNewLightBarLogic = featureFlags.isEnabled(Flags.NEW_LIGHT_BAR_LOGIC);
mDarkIconColor = ctx.getColor(R.color.dark_mode_icon_color_single_tone);
mLightIconColor = ctx.getColor(R.color.light_mode_icon_color_single_tone);
mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
@@ -188,51 +183,31 @@
final boolean last = mNavigationLight;
mHasLightNavigationBar = isLight(appearance, navigationBarMode,
APPEARANCE_LIGHT_NAVIGATION_BARS);
- if (mUseNewLightBarLogic) {
- final boolean ignoreScrimForce = mDirectReplying && mNavbarColorManagedByIme;
- final boolean darkForScrim = mForceDarkForScrim && !ignoreScrimForce;
- final boolean lightForScrim = mForceLightForScrim && !ignoreScrimForce;
- final boolean darkForQs = (mQsCustomizing || mQsExpanded) && !mBouncerVisible;
- final boolean darkForTop = darkForQs || mGlobalActionsVisible;
- mNavigationLight =
- ((mHasLightNavigationBar && !darkForScrim) || lightForScrim) && !darkForTop;
- if (DEBUG_NAVBAR) {
- mLastNavigationBarAppearanceChangedLog = getLogStringBuilder()
- .append("onNavigationBarAppearanceChanged()")
- .append(" appearance=").append(appearance)
- .append(" nbModeChanged=").append(nbModeChanged)
- .append(" navigationBarMode=").append(navigationBarMode)
- .append(" navbarColorManagedByIme=").append(navbarColorManagedByIme)
- .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
- .append(" ignoreScrimForce=").append(ignoreScrimForce)
- .append(" darkForScrim=").append(darkForScrim)
- .append(" lightForScrim=").append(lightForScrim)
- .append(" darkForQs=").append(darkForQs)
- .append(" darkForTop=").append(darkForTop)
- .append(" mNavigationLight=").append(mNavigationLight)
- .append(" last=").append(last)
- .append(" timestamp=").append(System.currentTimeMillis())
- .toString();
- if (DEBUG_LOGS) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
- }
- } else {
- mNavigationLight = mHasLightNavigationBar
- && (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim)
- && !mQsCustomizing;
- if (DEBUG_NAVBAR) {
- mLastNavigationBarAppearanceChangedLog = getLogStringBuilder()
- .append("onNavigationBarAppearanceChanged()")
- .append(" appearance=").append(appearance)
- .append(" nbModeChanged=").append(nbModeChanged)
- .append(" navigationBarMode=").append(navigationBarMode)
- .append(" navbarColorManagedByIme=").append(navbarColorManagedByIme)
- .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
- .append(" mNavigationLight=").append(mNavigationLight)
- .append(" last=").append(last)
- .append(" timestamp=").append(System.currentTimeMillis())
- .toString();
- if (DEBUG_LOGS) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
- }
+ final boolean ignoreScrimForce = mDirectReplying && mNavbarColorManagedByIme;
+ final boolean darkForScrim = mForceDarkForScrim && !ignoreScrimForce;
+ final boolean lightForScrim = mForceLightForScrim && !ignoreScrimForce;
+ final boolean darkForQs = (mQsCustomizing || mQsExpanded) && !mBouncerVisible;
+ final boolean darkForTop = darkForQs || mGlobalActionsVisible;
+ mNavigationLight =
+ ((mHasLightNavigationBar && !darkForScrim) || lightForScrim) && !darkForTop;
+ if (DEBUG_NAVBAR) {
+ mLastNavigationBarAppearanceChangedLog = getLogStringBuilder()
+ .append("onNavigationBarAppearanceChanged()")
+ .append(" appearance=").append(appearance)
+ .append(" nbModeChanged=").append(nbModeChanged)
+ .append(" navigationBarMode=").append(navigationBarMode)
+ .append(" navbarColorManagedByIme=").append(navbarColorManagedByIme)
+ .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
+ .append(" ignoreScrimForce=").append(ignoreScrimForce)
+ .append(" darkForScrim=").append(darkForScrim)
+ .append(" lightForScrim=").append(lightForScrim)
+ .append(" darkForQs=").append(darkForQs)
+ .append(" darkForTop=").append(darkForTop)
+ .append(" mNavigationLight=").append(mNavigationLight)
+ .append(" last=").append(last)
+ .append(" timestamp=").append(System.currentTimeMillis())
+ .toString();
+ if (DEBUG_LOGS) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
}
if (mNavigationLight != last) {
updateNavigation();
@@ -311,66 +286,39 @@
public void setScrimState(ScrimState scrimState, float scrimBehindAlpha,
GradientColors scrimInFrontColor) {
- if (mUseNewLightBarLogic) {
- boolean bouncerVisibleLast = mBouncerVisible;
- boolean forceDarkForScrimLast = mForceDarkForScrim;
- boolean forceLightForScrimLast = mForceLightForScrim;
- mBouncerVisible =
- scrimState == ScrimState.BOUNCER || scrimState == ScrimState.BOUNCER_SCRIMMED;
- final boolean forceForScrim = mBouncerVisible
- || scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
- final boolean scrimColorIsLight = scrimInFrontColor.supportsDarkText();
+ boolean bouncerVisibleLast = mBouncerVisible;
+ boolean forceDarkForScrimLast = mForceDarkForScrim;
+ boolean forceLightForScrimLast = mForceLightForScrim;
+ mBouncerVisible =
+ scrimState == ScrimState.BOUNCER || scrimState == ScrimState.BOUNCER_SCRIMMED;
+ final boolean forceForScrim = mBouncerVisible
+ || scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
+ final boolean scrimColorIsLight = scrimInFrontColor.supportsDarkText();
- mForceDarkForScrim = forceForScrim && !scrimColorIsLight;
- mForceLightForScrim = forceForScrim && scrimColorIsLight;
- if (mBouncerVisible != bouncerVisibleLast) {
- reevaluate();
- } else if (mHasLightNavigationBar) {
- if (mForceDarkForScrim != forceDarkForScrimLast) reevaluate();
- } else {
- if (mForceLightForScrim != forceLightForScrimLast) reevaluate();
- }
- if (DEBUG_NAVBAR) {
- mLastSetScrimStateLog = getLogStringBuilder()
- .append("setScrimState()")
- .append(" scrimState=").append(scrimState)
- .append(" scrimBehindAlpha=").append(scrimBehindAlpha)
- .append(" scrimInFrontColor=").append(scrimInFrontColor)
- .append(" forceForScrim=").append(forceForScrim)
- .append(" scrimColorIsLight=").append(scrimColorIsLight)
- .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
- .append(" mBouncerVisible=").append(mBouncerVisible)
- .append(" mForceDarkForScrim=").append(mForceDarkForScrim)
- .append(" mForceLightForScrim=").append(mForceLightForScrim)
- .append(" timestamp=").append(System.currentTimeMillis())
- .toString();
- if (DEBUG_LOGS) Log.d(TAG, mLastSetScrimStateLog);
- }
+ mForceDarkForScrim = forceForScrim && !scrimColorIsLight;
+ mForceLightForScrim = forceForScrim && scrimColorIsLight;
+ if (mBouncerVisible != bouncerVisibleLast) {
+ reevaluate();
+ } else if (mHasLightNavigationBar) {
+ if (mForceDarkForScrim != forceDarkForScrimLast) reevaluate();
} else {
- boolean forceDarkForScrimLast = mForceDarkForScrim;
- // For BOUNCER/BOUNCER_SCRIMMED cases, we assume that alpha is always below threshold.
- // This enables IMEs to control the navigation bar color.
- // For other cases, scrim should be able to veto the light navigation bar.
- // NOTE: this was also wrong for S and has been removed in the new logic.
- mForceDarkForScrim = scrimState != ScrimState.BOUNCER
- && scrimState != ScrimState.BOUNCER_SCRIMMED
- && scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD
- && !scrimInFrontColor.supportsDarkText();
- if (mHasLightNavigationBar && (mForceDarkForScrim != forceDarkForScrimLast)) {
- reevaluate();
- }
- if (DEBUG_NAVBAR) {
- mLastSetScrimStateLog = getLogStringBuilder()
- .append("setScrimState()")
- .append(" scrimState=").append(scrimState)
- .append(" scrimBehindAlpha=").append(scrimBehindAlpha)
- .append(" scrimInFrontColor=").append(scrimInFrontColor)
- .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
- .append(" mForceDarkForScrim=").append(mForceDarkForScrim)
- .append(" timestamp=").append(System.currentTimeMillis())
- .toString();
- if (DEBUG_LOGS) Log.d(TAG, mLastSetScrimStateLog);
- }
+ if (mForceLightForScrim != forceLightForScrimLast) reevaluate();
+ }
+ if (DEBUG_NAVBAR) {
+ mLastSetScrimStateLog = getLogStringBuilder()
+ .append("setScrimState()")
+ .append(" scrimState=").append(scrimState)
+ .append(" scrimBehindAlpha=").append(scrimBehindAlpha)
+ .append(" scrimInFrontColor=").append(scrimInFrontColor)
+ .append(" forceForScrim=").append(forceForScrim)
+ .append(" scrimColorIsLight=").append(scrimColorIsLight)
+ .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
+ .append(" mBouncerVisible=").append(mBouncerVisible)
+ .append(" mForceDarkForScrim=").append(mForceDarkForScrim)
+ .append(" mForceLightForScrim=").append(mForceLightForScrim)
+ .append(" timestamp=").append(System.currentTimeMillis())
+ .toString();
+ if (DEBUG_LOGS) Log.d(TAG, mLastSetScrimStateLog);
}
}
@@ -498,7 +446,6 @@
private final DarkIconDispatcher mDarkIconDispatcher;
private final BatteryController mBatteryController;
private final NavigationModeController mNavModeController;
- private final FeatureFlags mFeatureFlags;
private final DumpManager mDumpManager;
private final DisplayTracker mDisplayTracker;
@@ -507,14 +454,12 @@
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
- FeatureFlags featureFlags,
DumpManager dumpManager,
DisplayTracker displayTracker) {
mDarkIconDispatcher = darkIconDispatcher;
mBatteryController = batteryController;
mNavModeController = navModeController;
- mFeatureFlags = featureFlags;
mDumpManager = dumpManager;
mDisplayTracker = displayTracker;
}
@@ -522,7 +467,7 @@
/** Create an {@link LightBarController} */
public LightBarController create(Context context) {
return new LightBarController(context, mDarkIconDispatcher, mBatteryController,
- mNavModeController, mFeatureFlags, mDumpManager, mDisplayTracker);
+ mNavModeController, mDumpManager, mDisplayTracker);
}
}
}
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..e18c9d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -33,14 +33,11 @@
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider;
-import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.wm.shell.bubbles.Bubbles;
@@ -91,8 +88,6 @@
private final ArrayList<Rect> mTintAreas = new ArrayList<>();
private final Context mContext;
- private final DemoModeController mDemoModeController;
-
private final FeatureFlags mFeatureFlags;
private int mAodIconAppearTranslation;
@@ -139,8 +134,7 @@
wakeUpCoordinator.addListener(this);
mBypassController = keyguardBypassController;
mBubblesOptional = bubblesOptional;
- mDemoModeController = demoModeController;
- mDemoModeController.addCallback(this);
+ demoModeController.addCallback(this);
mStatusBarWindowController = statusBarWindowController;
mScreenOffAnimationController = screenOffAnimationController;
notificationListener.addNotificationSettingsListener(mSettingsListener);
@@ -163,7 +157,6 @@
LayoutInflater layoutInflater = LayoutInflater.from(context);
mNotificationIconArea = inflateIconArea(layoutInflater);
mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);
-
}
/**
@@ -185,16 +178,6 @@
updateIconLayoutParams(mContext);
}
- /**
- * Update position of the view, with optional animation
- */
- public void updatePosition(int x, AnimationProperties props, boolean animate) {
- if (mAodIcons != null) {
- PropertyAnimator.setProperty(mAodIcons, AnimatableProperty.TRANSLATION_X, x, props,
- animate);
- }
- }
-
public void setupShelf(NotificationShelfController notificationShelfController) {
NotificationShelfController.assertRefactorFlagDisabled(mFeatureFlags);
mShelfIcons = notificationShelfController.getShelfIcons();
@@ -239,7 +222,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);
@@ -303,6 +286,7 @@
}
return true;
}
+
/**
* Updates the notifications with the given list of notifications to display.
*/
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..3770c1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -54,19 +54,13 @@
* correctly on the screen.
*/
public class NotificationIconContainer extends ViewGroup {
- /**
- * A float value indicating how much before the overflow start the icons should transform into
- * a dot. A value of 0 means that they are exactly at the end and a value of 1 means it starts
- * 1 icon width early.
- */
- public static final float OVERFLOW_EARLY_AMOUNT = 0.2f;
private static final int NO_VALUE = Integer.MIN_VALUE;
private static final String TAG = "NotificationIconContainer";
private static final boolean DEBUG = false;
private static final boolean DEBUG_OVERFLOW = false;
private static final int CANNED_ANIMATION_DURATION = 100;
private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
+ private final AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
@Override
public AnimationFilter getAnimationFilter() {
@@ -75,7 +69,7 @@
}.setDuration(200);
private static final AnimationProperties ICON_ANIMATION_PROPERTIES = new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter()
+ private final AnimationFilter mAnimationFilter = new AnimationFilter()
.animateX()
.animateY()
.animateAlpha()
@@ -92,7 +86,7 @@
* Temporary AnimationProperties to avoid unnecessary allocations.
*/
private static final AnimationProperties sTempProperties = new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter();
+ private final AnimationFilter mAnimationFilter = new AnimationFilter();
@Override
public AnimationFilter getAnimationFilter() {
@@ -101,7 +95,7 @@
};
private static final AnimationProperties ADD_ICON_PROPERTIES = new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
+ private final AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
@Override
public AnimationFilter getAnimationFilter() {
@@ -115,7 +109,7 @@
*/
private static final AnimationProperties UNISOLATION_PROPERTY_OTHERS
= new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
+ private final AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
@Override
public AnimationFilter getAnimationFilter() {
@@ -128,7 +122,7 @@
* This animates the translation back to the right position.
*/
private static final AnimationProperties UNISOLATION_PROPERTY = new AnimationProperties() {
- private AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
+ private final AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
@Override
public AnimationFilter getAnimationFilter() {
@@ -147,7 +141,6 @@
private boolean mIsStaticLayout = true;
private final HashMap<View, IconState> mIconStates = new HashMap<>();
private int mDotPadding;
- private int mStaticDotRadius;
private int mStaticDotDiameter;
private int mActualLayoutWidth = NO_VALUE;
private float mActualPaddingEnd = NO_VALUE;
@@ -170,7 +163,7 @@
private boolean mIsShowingOverflowDot;
private StatusBarIconView mIsolatedIcon;
private Rect mIsolatedIconLocation;
- private int[] mAbsolutePosition = new int[2];
+ private final int[] mAbsolutePosition = new int[2];
private View mIsolatedIconForAnimation;
private int mThemedTextColorPrimary;
@@ -186,8 +179,8 @@
mMaxStaticIcons = getResources().getInteger(R.integer.max_notif_static_icons);
mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);
- mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
- mStaticDotDiameter = 2 * mStaticDotRadius;
+ int staticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+ mStaticDotDiameter = 2 * staticDotRadius;
final Context themedContext = new ContextThemeWrapper(getContext(),
com.android.internal.R.style.Theme_DeviceDefault_DayNight);
@@ -339,6 +332,7 @@
}
}
if (child instanceof StatusBarIconView) {
+ ((StatusBarIconView) child).updateIconDimens();
((StatusBarIconView) child).setDozing(mDozing, false, 0);
}
}
@@ -447,9 +441,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 +488,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 +533,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;
}
}
@@ -695,7 +692,6 @@
}
public class IconState extends ViewState {
- public static final int NO_VALUE = NotificationIconContainer.NO_VALUE;
public float iconAppearAmount = 1.0f;
public float clampedAppearAmount = 1.0f;
public int visibleState;
@@ -813,8 +809,6 @@
super.applyToView(view);
}
sTempProperties.setAnimationEndAction(null);
- boolean inShelf = iconAppearAmount == 1.0f;
- icon.setIsInShelf(inShelf);
}
justAdded = false;
justReplaced = false;
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..3cd09a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -52,14 +52,12 @@
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;
-import com.android.systemui.flags.FeatureFlags;
-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;
@@ -249,8 +247,6 @@
private int mScrimsVisibility;
private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
private final LargeScreenShadeInterpolator mLargeScreenShadeInterpolator;
- private final FeatureFlags mFeatureFlags;
- private final boolean mUseNewLightBarLogic;
private Consumer<Integer> mScrimVisibleListener;
private boolean mBlankScreen;
private boolean mScreenBlankingCallbackCalled;
@@ -303,12 +299,9 @@
PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
KeyguardTransitionInteractor keyguardTransitionInteractor,
@Main CoroutineDispatcher mainDispatcher,
- LargeScreenShadeInterpolator largeScreenShadeInterpolator,
- FeatureFlags featureFlags) {
+ LargeScreenShadeInterpolator largeScreenShadeInterpolator) {
mScrimStateListener = lightBarController::setScrimState;
mLargeScreenShadeInterpolator = largeScreenShadeInterpolator;
- mFeatureFlags = featureFlags;
- mUseNewLightBarLogic = featureFlags.isEnabled(Flags.NEW_LIGHT_BAR_LOGIC);
mDefaultScrimAlpha = BUSY_SCRIM_ALPHA;
mKeyguardStateController = keyguardStateController;
@@ -1153,13 +1146,7 @@
if (mClipsQsScrim && mQsBottomVisible) {
alpha = mNotificationsAlpha;
}
- if (mUseNewLightBarLogic) {
- mScrimStateListener.accept(mState, alpha, mColors);
- } else {
- // NOTE: This wasn't wrong, but it implied that each scrim might have different colors,
- // when in fact they all share the same GradientColors instance, which we own.
- mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
- }
+ mScrimStateListener.accept(mState, alpha, mColors);
}
private void dispatchScrimsVisible() {
@@ -1483,15 +1470,15 @@
int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
mColors.setMainColor(background);
mColors.setSecondaryColor(accent);
- if (mUseNewLightBarLogic) {
- final boolean isBackgroundLight = !ContrastColorUtil.isColorDark(background);
- mColors.setSupportsDarkText(isBackgroundLight);
- } else {
- // NOTE: This was totally backward, but LightBarController was flipping it back.
- // There may be other consumers of this which would struggle though
- mColors.setSupportsDarkText(
- ColorUtils.calculateContrast(mColors.getMainColor(), Color.WHITE) > 4.5);
+ final boolean isBackgroundLight = !ContrastColorUtil.isColorDark(background);
+ mColors.setSupportsDarkText(isBackgroundLight);
+
+ 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..42b0a4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -17,7 +17,6 @@
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE_NEW;
-import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI_NEW;
import android.annotation.Nullable;
@@ -43,12 +42,10 @@
import com.android.systemui.statusbar.BaseStatusBarFrameLayout;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
-import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder;
@@ -97,16 +94,9 @@
*/
void setIcon(String slot, int resourceId, CharSequence contentDescription);
- /** */
- void setWifiIcon(String slot, WifiIconState state);
-
/**
* Sets up a wifi icon using the new data pipeline. No effect if the wifi icon has already been
* set up (inflated and added to the view hierarchy).
- *
- * This method completely replaces {@link #setWifiIcon} with the information from the new wifi
- * data pipeline. Icons will automatically keep their state up to date, so we don't have to
- * worry about funneling state objects through anymore.
*/
void setNewWifiIcon();
@@ -370,7 +360,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 +385,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.
@@ -408,13 +398,7 @@
mMobileIconsViewModel = null;
}
- if (statusBarPipelineFlags.runNewWifiIconBackend()) {
- // This starts the flow for the new pipeline, and will notify us of changes if
- // {@link StatusBarPipelineFlags#useNewWifiIcon} is also true.
- mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, mLocation);
- } else {
- mWifiViewModel = null;
- }
+ mWifiViewModel = wifiUiAdapter.bindGroup(mGroup, mLocation);
}
public boolean isDemoable() {
@@ -462,9 +446,6 @@
case TYPE_ICON:
return addIcon(index, slot, blocked, holder.getIcon());
- case TYPE_WIFI:
- return addWifiIcon(index, slot, holder.getWifiState());
-
case TYPE_WIFI_NEW:
return addNewWifiIcon(index, slot);
@@ -487,29 +468,7 @@
return view;
}
- @VisibleForTesting
- protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) {
- if (mStatusBarPipelineFlags.useNewWifiIcon()) {
- throw new IllegalStateException("Attempting to add a wifi icon while the new "
- + "icons are enabled is not supported");
- }
-
- final StatusBarWifiView view = onCreateStatusBarWifiView(slot);
- view.applyWifiState(state);
- mGroup.addView(view, index, onCreateLayoutParams());
-
- if (mIsInDemoMode) {
- mDemoStatusIcons.addDemoWifiView(state);
- }
- return view;
- }
-
protected StatusIconDisplayable addNewWifiIcon(int index, String slot) {
- if (!mStatusBarPipelineFlags.useNewWifiIcon()) {
- throw new IllegalStateException("Attempting to add a wifi icon using the new"
- + "pipeline, but the enabled flag is false.");
- }
-
ModernStatusBarWifiView view = onCreateModernStatusBarWifiView(slot);
mGroup.addView(view, index, onCreateLayoutParams());
@@ -573,11 +532,6 @@
return new StatusBarIconView(mContext, slot, null, blocked);
}
- private StatusBarWifiView onCreateStatusBarWifiView(String slot) {
- StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, slot);
- return view;
- }
-
private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) {
return ModernStatusBarWifiView.constructAndBind(mContext, slot, mWifiViewModel);
}
@@ -609,13 +563,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) {
@@ -644,9 +594,6 @@
case TYPE_ICON:
onSetIcon(viewIndex, holder.getIcon());
return;
- case TYPE_WIFI:
- onSetWifiIcon(viewIndex, holder.getWifiState());
- return;
case TYPE_MOBILE:
onSetMobileIcon(viewIndex, holder.getMobileState());
return;
@@ -659,23 +606,6 @@
}
}
- public void onSetWifiIcon(int viewIndex, WifiIconState state) {
- View view = mGroup.getChildAt(viewIndex);
- if (view instanceof StatusBarWifiView) {
- ((StatusBarWifiView) view).applyWifiState(state);
- } else if (view instanceof ModernStatusBarWifiView) {
- // ModernStatusBarWifiView will automatically apply state based on its callbacks, so
- // we don't need to call applyWifiState.
- } else {
- throw new IllegalStateException("View at " + viewIndex + " must be of type "
- + "StatusBarWifiView or ModernStatusBarWifiView");
- }
-
- if (mIsInDemoMode) {
- mDemoStatusIcons.updateWifiState(state);
- }
- }
-
public void onSetMobileIcon(int viewIndex, MobileIconState state) {
View view = mGroup.getChildAt(viewIndex);
if (view instanceof StatusBarMobileView) {
@@ -707,9 +637,7 @@
mIsInDemoMode = true;
if (mDemoStatusIcons == null) {
mDemoStatusIcons = createDemoStatusIcons();
- if (mStatusBarPipelineFlags.useNewWifiIcon()) {
- mDemoStatusIcons.addModernWifiView(mWifiViewModel);
- }
+ mDemoStatusIcons.addModernWifiView(mWifiViewModel);
}
mDemoStatusIcons.onDemoModeStarted();
}
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..d1a02d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -40,7 +40,6 @@
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -109,6 +108,7 @@
}
group.setController(this);
+ group.reloadDimens();
mIconGroups.add(group);
List<Slot> allSlots = mStatusBarIconList.getSlots();
for (int i = 0; i < allSlots.size(); i++) {
@@ -201,35 +201,7 @@
}
@Override
- public void setWifiIcon(String slot, WifiIconState state) {
- if (mStatusBarPipelineFlags.useNewWifiIcon()) {
- Log.d(TAG, "ignoring old pipeline callback because the new wifi icon is enabled");
- return;
- }
-
- if (state == null) {
- removeIcon(slot, 0);
- return;
- }
-
- StatusBarIconHolder holder = mStatusBarIconList.getIconHolder(slot, 0);
- if (holder == null) {
- holder = StatusBarIconHolder.fromWifiIconState(state);
- setIcon(slot, holder);
- } else {
- holder.setWifiState(state);
- handleSet(slot, holder);
- }
- }
-
-
- @Override
public void setNewWifiIcon() {
- if (!mStatusBarPipelineFlags.useNewWifiIcon()) {
- Log.d(TAG, "ignoring new pipeline callback because the new wifi icon is disabled");
- return;
- }
-
String slot = mContext.getString(com.android.internal.R.string.status_bar_wifi);
StatusBarIconHolder holder = mStatusBarIconList.getIconHolder(slot, /* tag= */ 0);
if (holder == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
index 833cb93..01fd247 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -25,7 +25,6 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel;
import java.lang.annotation.Retention;
@@ -36,7 +35,6 @@
*/
public class StatusBarIconHolder {
public static final int TYPE_ICON = 0;
- public static final int TYPE_WIFI = 1;
public static final int TYPE_MOBILE = 2;
/**
* TODO (b/249790733): address this once the new pipeline is in place
@@ -65,7 +63,6 @@
@IntDef({
TYPE_ICON,
- TYPE_WIFI,
TYPE_MOBILE,
TYPE_MOBILE_NEW,
TYPE_WIFI_NEW
@@ -74,7 +71,6 @@
@interface IconType {}
private StatusBarIcon mIcon;
- private WifiIconState mWifiState;
private MobileIconState mMobileState;
private @IconType int mType = TYPE_ICON;
private int mTag = 0;
@@ -83,7 +79,6 @@
public static String getTypeString(@IconType int type) {
switch(type) {
case TYPE_ICON: return "ICON";
- case TYPE_WIFI: return "WIFI_OLD";
case TYPE_MOBILE: return "MOBILE_OLD";
case TYPE_MOBILE_NEW: return "MOBILE_NEW";
case TYPE_WIFI_NEW: return "WIFI_NEW";
@@ -101,25 +96,6 @@
return wrapper;
}
- /** */
- public static StatusBarIconHolder fromResId(
- Context context,
- int resId,
- CharSequence contentDescription) {
- StatusBarIconHolder holder = new StatusBarIconHolder();
- holder.mIcon = new StatusBarIcon(UserHandle.SYSTEM, context.getPackageName(),
- Icon.createWithResource( context, resId), 0, 0, contentDescription);
- return holder;
- }
-
- /** */
- public static StatusBarIconHolder fromWifiIconState(WifiIconState state) {
- StatusBarIconHolder holder = new StatusBarIconHolder();
- holder.mWifiState = state;
- holder.mType = TYPE_WIFI;
- return holder;
- }
-
/** Creates a new holder with for the new wifi icon. */
public static StatusBarIconHolder forNewWifiIcon() {
StatusBarIconHolder holder = new StatusBarIconHolder();
@@ -178,15 +154,6 @@
}
@Nullable
- public WifiIconState getWifiState() {
- return mWifiState;
- }
-
- public void setWifiState(WifiIconState state) {
- mWifiState = state;
- }
-
- @Nullable
public MobileIconState getMobileState() {
return mMobileState;
}
@@ -199,8 +166,6 @@
switch (mType) {
case TYPE_ICON:
return mIcon.visible;
- case TYPE_WIFI:
- return mWifiState.visible;
case TYPE_MOBILE:
return mMobileState.visible;
case TYPE_MOBILE_NEW:
@@ -223,10 +188,6 @@
mIcon.visible = visible;
break;
- case TYPE_WIFI:
- mWifiState.visible = visible;
- break;
-
case TYPE_MOBILE:
mMobileState.visible = visible;
break;
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/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index f79a081..ec0c00e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -54,8 +54,10 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeViewController;
@@ -94,6 +96,7 @@
class StatusBarNotificationActivityStarter implements NotificationActivityStarter {
private final Context mContext;
+ private final int mDisplayId;
private final Handler mMainThreadHandler;
private final Executor mUiBgExecutor;
@@ -120,12 +123,12 @@
private final MetricsLogger mMetricsLogger;
private final StatusBarNotificationActivityStarterLogger mLogger;
- private final CentralSurfaces mCentralSurfaces;
private final NotificationPresenter mPresenter;
private final ShadeViewController mShadeViewController;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
+ private final PowerInteractor mPowerInteractor;
private final UserTracker mUserTracker;
private final OnUserInteractionCallback mOnUserInteractionCallback;
@@ -134,6 +137,7 @@
@Inject
StatusBarNotificationActivityStarter(
Context context,
+ @DisplayId int displayId,
Handler mainThreadHandler,
Executor uiBgExecutor,
NotificationVisibilityProvider visibilityProvider,
@@ -156,16 +160,17 @@
MetricsLogger metricsLogger,
StatusBarNotificationActivityStarterLogger logger,
OnUserInteractionCallback onUserInteractionCallback,
- CentralSurfaces centralSurfaces,
NotificationPresenter presenter,
ShadeViewController shadeViewController,
NotificationShadeWindowController notificationShadeWindowController,
ActivityLaunchAnimator activityLaunchAnimator,
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
LaunchFullScreenIntentProvider launchFullScreenIntentProvider,
+ PowerInteractor powerInteractor,
FeatureFlags featureFlags,
UserTracker userTracker) {
mContext = context;
+ mDisplayId = displayId;
mMainThreadHandler = mainThreadHandler;
mUiBgExecutor = uiBgExecutor;
mVisibilityProvider = visibilityProvider;
@@ -190,12 +195,11 @@
mMetricsLogger = metricsLogger;
mLogger = logger;
mOnUserInteractionCallback = onUserInteractionCallback;
- // TODO: use KeyguardStateController#isOccluded to remove this dependency
- mCentralSurfaces = centralSurfaces;
mPresenter = presenter;
mShadeViewController = shadeViewController;
mActivityLaunchAnimator = activityLaunchAnimator;
mNotificationAnimationProvider = notificationAnimationProvider;
+ mPowerInteractor = powerInteractor;
mUserTracker = userTracker;
launchFullScreenIntentProvider.registerListener(entry -> launchFullScreenIntent(entry));
@@ -280,7 +284,7 @@
mShadeController.addPostCollapseAction(runnable);
mShadeController.collapseShade(true /* animate */);
} else if (mKeyguardStateController.isShowing()
- && mCentralSurfaces.isOccluded()) {
+ && mKeyguardStateController.isOccluded()) {
mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
mShadeController.collapseShade();
} else {
@@ -452,11 +456,11 @@
long eventTime = row.getAndResetLastActionUpTime();
Bundle options = eventTime > 0
? getActivityOptions(
- mCentralSurfaces.getDisplayId(),
+ mDisplayId,
adapter,
mKeyguardStateController.isShowing(),
eventTime)
- : getActivityOptions(mCentralSurfaces.getDisplayId(), adapter);
+ : getActivityOptions(mDisplayId, adapter);
int result = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
null, null, options);
mLogger.logSendPendingIntent(entry, intent, result);
@@ -491,7 +495,7 @@
(adapter) -> TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
.startActivities(getActivityOptions(
- mCentralSurfaces.getDisplayId(),
+ mDisplayId,
adapter),
new UserHandle(UserHandle.getUserId(appUid))));
});
@@ -539,7 +543,7 @@
mActivityLaunchAnimator.startIntentWithAnimation(animationController, animate,
intent.getPackage(),
(adapter) -> tsb.startActivities(
- getActivityOptions(mCentralSurfaces.getDisplayId(), adapter),
+ getActivityOptions(mDisplayId, adapter),
mUserTracker.getUserHandle()));
});
return true;
@@ -592,7 +596,7 @@
try {
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
entry.getKey());
- mCentralSurfaces.wakeUpForFullScreenIntent();
+ mPowerInteractor.wakeUpForFullScreenIntent();
ActivityOptions options = ActivityOptions.makeBasic();
options.setPendingIntentBackgroundActivityStartMode(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index d731f88..6919996 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -30,7 +30,6 @@
import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.SignalCallback;
-import com.android.systemui.statusbar.connectivity.WifiIndicators;
import com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -51,7 +50,6 @@
private final String mSlotAirplane;
private final String mSlotMobile;
- private final String mSlotWifi;
private final String mSlotEthernet;
private final String mSlotVpn;
private final String mSlotNoCalling;
@@ -67,17 +65,14 @@
private boolean mHideAirplane;
private boolean mHideMobile;
- private boolean mHideWifi;
private boolean mHideEthernet;
private boolean mActivityEnabled;
// Track as little state as possible, and only for padding purposes
private boolean mIsAirplaneMode = false;
- private boolean mIsWifiEnabled = false;
private ArrayList<MobileIconState> mMobileStates = new ArrayList<>();
private ArrayList<CallIndicatorIconState> mCallIndicatorStates = new ArrayList<>();
- private WifiIconState mWifiIconState = new WifiIconState();
private boolean mInitialized;
@Inject
@@ -99,7 +94,6 @@
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
- mSlotWifi = mContext.getString(com.android.internal.R.string.status_bar_wifi);
mSlotEthernet = mContext.getString(com.android.internal.R.string.status_bar_ethernet);
mSlotVpn = mContext.getString(com.android.internal.R.string.status_bar_vpn);
mSlotNoCalling = mContext.getString(com.android.internal.R.string.status_bar_no_calling);
@@ -154,15 +148,13 @@
ArraySet<String> hideList = StatusBarIconController.getIconHideList(mContext, newValue);
boolean hideAirplane = hideList.contains(mSlotAirplane);
boolean hideMobile = hideList.contains(mSlotMobile);
- boolean hideWifi = hideList.contains(mSlotWifi);
boolean hideEthernet = hideList.contains(mSlotEthernet);
if (hideAirplane != mHideAirplane || hideMobile != mHideMobile
- || hideEthernet != mHideEthernet || hideWifi != mHideWifi) {
+ || hideEthernet != mHideEthernet) {
mHideAirplane = hideAirplane;
mHideMobile = hideMobile;
mHideEthernet = hideEthernet;
- mHideWifi = hideWifi;
// Re-register to get new callbacks.
mNetworkController.removeCallback(this);
mNetworkController.addCallback(this);
@@ -170,56 +162,6 @@
}
@Override
- public void setWifiIndicators(@NonNull WifiIndicators indicators) {
- if (DEBUG) {
- Log.d(TAG, "setWifiIndicators: " + indicators);
- }
- boolean visible = indicators.statusIcon.visible && !mHideWifi;
- boolean in = indicators.activityIn && mActivityEnabled && visible;
- boolean out = indicators.activityOut && mActivityEnabled && visible;
- mIsWifiEnabled = indicators.enabled;
-
- WifiIconState newState = mWifiIconState.copy();
-
- if (mWifiIconState.noDefaultNetwork && mWifiIconState.noNetworksAvailable
- && !mIsAirplaneMode) {
- newState.visible = true;
- newState.resId = R.drawable.ic_qs_no_internet_unavailable;
- } else if (mWifiIconState.noDefaultNetwork && !mWifiIconState.noNetworksAvailable
- && (!mIsAirplaneMode || (mIsAirplaneMode && mIsWifiEnabled))) {
- newState.visible = true;
- newState.resId = R.drawable.ic_qs_no_internet_available;
- } else {
- newState.visible = visible;
- newState.resId = indicators.statusIcon.icon;
- newState.activityIn = in;
- newState.activityOut = out;
- newState.contentDescription = indicators.statusIcon.contentDescription;
- MobileIconState first = getFirstMobileState();
- newState.signalSpacerVisible = first != null && first.typeId != 0;
- }
- newState.slot = mSlotWifi;
- newState.airplaneSpacerVisible = mIsAirplaneMode;
- updateWifiIconWithState(newState);
- mWifiIconState = newState;
- }
-
- private void updateShowWifiSignalSpacer(WifiIconState state) {
- MobileIconState first = getFirstMobileState();
- state.signalSpacerVisible = first != null && first.typeId != 0;
- }
-
- private void updateWifiIconWithState(WifiIconState state) {
- if (DEBUG) Log.d(TAG, "WifiIconState: " + state == null ? "" : state.toString());
- if (state.visible && state.resId > 0) {
- mIconController.setWifiIcon(mSlotWifi, state);
- mIconController.setIconVisibility(mSlotWifi, true);
- } else {
- mIconController.setIconVisibility(mSlotWifi, false);
- }
- }
-
- @Override
public void setCallIndicator(@NonNull IconState statusIcon, int subId) {
if (DEBUG) {
Log.d(TAG, "setCallIndicator: "
@@ -257,10 +199,6 @@
return;
}
- // Visibility of the data type indicator changed
- boolean typeChanged = indicators.statusType != state.typeId
- && (indicators.statusType == 0 || state.typeId == 0);
-
state.visible = indicators.statusIcon.visible && !mHideMobile;
state.strengthId = indicators.statusIcon.icon;
state.typeId = indicators.statusType;
@@ -277,15 +215,6 @@
}
// Always send a copy to maintain value type semantics
mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
-
- if (typeChanged) {
- WifiIconState wifiCopy = mWifiIconState.copy();
- updateShowWifiSignalSpacer(wifiCopy);
- if (!Objects.equals(wifiCopy, mWifiIconState)) {
- updateWifiIconWithState(wifiCopy);
- mWifiIconState = wifiCopy;
- }
- }
}
private CallIndicatorIconState getNoCallingState(int subId) {
@@ -308,15 +237,6 @@
return null;
}
- private MobileIconState getFirstMobileState() {
- if (mMobileStates.size() > 0) {
- return mMobileStates.get(0);
- }
-
- return null;
- }
-
-
/**
* It is expected that a call to setSubs will be immediately followed by setMobileDataIndicators
* so we don't have to update the icon manager at this point, just remove the old ones
@@ -504,60 +424,6 @@
}
}
- public static class WifiIconState extends SignalIconState{
- public int resId;
- public boolean airplaneSpacerVisible;
- public boolean signalSpacerVisible;
- public boolean noDefaultNetwork;
- public boolean noValidatedNetwork;
- public boolean noNetworksAvailable;
-
- @Override
- public boolean equals(Object o) {
- // Skipping reference equality bc this should be more of a value type
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- if (!super.equals(o)) {
- return false;
- }
- WifiIconState that = (WifiIconState) o;
- return resId == that.resId
- && airplaneSpacerVisible == that.airplaneSpacerVisible
- && signalSpacerVisible == that.signalSpacerVisible
- && noDefaultNetwork == that.noDefaultNetwork
- && noValidatedNetwork == that.noValidatedNetwork
- && noNetworksAvailable == that.noNetworksAvailable;
- }
-
- public void copyTo(WifiIconState other) {
- super.copyTo(other);
- other.resId = resId;
- other.airplaneSpacerVisible = airplaneSpacerVisible;
- other.signalSpacerVisible = signalSpacerVisible;
- other.noDefaultNetwork = noDefaultNetwork;
- other.noValidatedNetwork = noValidatedNetwork;
- other.noNetworksAvailable = noNetworksAvailable;
- }
-
- public WifiIconState copy() {
- WifiIconState newState = new WifiIconState();
- copyTo(newState);
- return newState;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(super.hashCode(),
- resId, airplaneSpacerVisible, signalSpacerVisible, noDefaultNetwork,
- noValidatedNetwork, noNetworksAvailable);
- }
-
- @Override public String toString() {
- return "WifiIconState(resId=" + resId + ", visible=" + visible + ")";
- }
- }
-
/**
* A little different. This one delegates to SignalDrawable instead of a specific resId
*/
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/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index 97a1bd1..c8e73d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.phone.SystemBarAttributesListener;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
@@ -72,6 +73,13 @@
/** */
@Provides
@StatusBarFragmentScope
+ static StatusBarLocation getStatusBarLocation() {
+ return StatusBarLocation.HOME;
+ }
+
+ /** */
+ @Provides
+ @StatusBarFragmentScope
@Named(START_SIDE_CONTENT)
static View startSideContent(@RootView PhoneStatusBarView view) {
return view.findViewById(R.id.status_bar_start_side_content);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
index 4a684d9..29829e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
@@ -45,18 +45,6 @@
fun runNewMobileIconsBackend(): Boolean =
featureFlags.isEnabled(Flags.NEW_STATUS_BAR_MOBILE_ICONS_BACKEND) || useNewMobileIcons()
- /** True if we should display the wifi icon using the new status bar data pipeline. */
- fun useNewWifiIcon(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON)
-
- /**
- * True if we should run the new wifi icon backend to get the logging.
- *
- * Does *not* affect whether we render the wifi icon using the new backend data. See
- * [useNewWifiIcon] for that.
- */
- fun runNewWifiIconBackend(): Boolean =
- featureFlags.isEnabled(Flags.NEW_STATUS_BAR_WIFI_ICON_BACKEND) || useNewWifiIcon()
-
/**
* Returns true if we should apply some coloring to the icons that were rendered with the new
* pipeline to help with debugging.
@@ -71,5 +59,5 @@
* @return true if this icon is controlled by any of the status bar pipeline flags
*/
fun isIconControlledByFlags(slotName: String): Boolean =
- slotName == wifiSlot && useNewWifiIcon() || slotName == mobileSlot && useNewMobileIcons()
+ slotName == wifiSlot || (slotName == mobileSlot && useNewMobileIcons())
}
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..a1b96dd 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
@@ -101,12 +101,7 @@
this.binding = bindingCreator.invoke()
}
- /**
- * Creates a [StatusBarIconView] that is always in DOT mode and adds it to this view.
- *
- * Mostly duplicated from [com.android.systemui.statusbar.StatusBarWifiView] and
- * [com.android.systemui.statusbar.StatusBarMobileView].
- */
+ /** Creates a [StatusBarIconView] that is always in DOT mode and adds it to this view. */
private fun initDotView() {
// TODO(b/238425913): Could we just have this dot view be part of the layout with a dot
// drawable so we don't need to inflate it manually? Would that not work with animations?
@@ -118,7 +113,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/pipeline/wifi/ui/WifiUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt
index 174298a..6d71823 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapter.kt
@@ -68,12 +68,7 @@
launch {
locationViewModel.wifiIcon.collect { wifiIcon ->
// Only notify the icon controller if we want to *render* the new icon.
- // Note that this flow may still run if
- // [statusBarPipelineFlags.runNewWifiIconBackend] is true because we may
- // want to get the logging data without rendering.
- if (
- wifiIcon is WifiIcon.Visible && statusBarPipelineFlags.useNewWifiIcon()
- ) {
+ if (wifiIcon is WifiIcon.Visible) {
iconController.setNewWifiIcon()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 3d16591..7df083afc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -19,6 +19,9 @@
import android.annotation.Nullable;
import android.view.View;
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -136,7 +139,7 @@
* A listener that will be notified whenever a change in battery level or power save mode has
* occurred.
*/
- interface BatteryStateChangeCallback {
+ interface BatteryStateChangeCallback extends Dumpable {
default void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
}
@@ -158,6 +161,11 @@
default void onIsBatteryDefenderChanged(boolean isBatteryDefender) {
}
+
+ @Override
+ default void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println(this);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index e69d86c..d5d8f4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -22,6 +22,7 @@
import static android.os.BatteryManager.EXTRA_PRESENT;
import static com.android.settingslib.fuelgauge.BatterySaverLogging.SAVER_ENABLED_QS;
+import static com.android.systemui.util.DumpUtilsKt.asIndenting;
import android.annotation.WorkerThread;
import android.content.BroadcastReceiver;
@@ -33,6 +34,7 @@
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerSaveState;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.view.View;
@@ -157,15 +159,29 @@
}
@Override
- public void dump(PrintWriter pw, String[] args) {
- pw.println("BatteryController state:");
- pw.print(" mLevel="); pw.println(mLevel);
- pw.print(" mPluggedIn="); pw.println(mPluggedIn);
- pw.print(" mCharging="); pw.println(mCharging);
- pw.print(" mCharged="); pw.println(mCharged);
- pw.print(" mIsBatteryDefender="); pw.println(mIsBatteryDefender);
- pw.print(" mPowerSave="); pw.println(mPowerSave);
- pw.print(" mStateUnknown="); pw.println(mStateUnknown);
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ IndentingPrintWriter ipw = asIndenting(pw);
+ ipw.println("BatteryController state:");
+ ipw.increaseIndent();
+ ipw.print("mHasReceivedBattery="); ipw.println(mHasReceivedBattery);
+ ipw.print("mLevel="); ipw.println(mLevel);
+ ipw.print("mPluggedIn="); ipw.println(mPluggedIn);
+ ipw.print("mCharging="); ipw.println(mCharging);
+ ipw.print("mCharged="); ipw.println(mCharged);
+ ipw.print("mIsBatteryDefender="); ipw.println(mIsBatteryDefender);
+ ipw.print("mPowerSave="); ipw.println(mPowerSave);
+ ipw.print("mStateUnknown="); ipw.println(mStateUnknown);
+ ipw.println("Callbacks:------------------");
+ // Since the above lines are already indented, we need to indent twice for the callbacks.
+ ipw.increaseIndent();
+ synchronized (mChangeCallbacks) {
+ final int n = mChangeCallbacks.size();
+ for (int i = 0; i < n; i++) {
+ mChangeCallbacks.get(i).dump(ipw, args);
+ }
+ }
+ ipw.decreaseIndent();
+ ipw.println("------------------");
}
@Override
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/window/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
index 4a9921e..24987ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.java
@@ -241,9 +241,9 @@
}
lp.providedInsets = new InsetsFrameProvider[] {
new InsetsFrameProvider(mInsetsSourceOwner, 0, statusBars())
- .setInsetsSize(Insets.of(0, height, 0, 0)),
+ .setInsetsSize(getInsets(height)),
new InsetsFrameProvider(mInsetsSourceOwner, 0, tappableElement())
- .setInsetsSize(Insets.of(0, height, 0, 0)),
+ .setInsetsSize(getInsets(height)),
gestureInsetsProvider
};
return lp;
@@ -308,12 +308,37 @@
mLpChanged.height =
state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : mBarHeight;
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+ int height = SystemBarUtils.getStatusBarHeightForRotation(mContext, rot);
mLpChanged.paramsForRotation[rot].height =
- state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT :
- SystemBarUtils.getStatusBarHeightForRotation(mContext, rot);
+ state.mIsLaunchAnimationRunning ? ViewGroup.LayoutParams.MATCH_PARENT : height;
+ // The status bar height could change at runtime if one display has a cutout while
+ // another doesn't (like some foldables). It could also change when using debug cutouts.
+ // So, we need to re-fetch the height and re-apply it to the insets each time to avoid
+ // bugs like b/290300359.
+ InsetsFrameProvider[] providers = mLpChanged.paramsForRotation[rot].providedInsets;
+ if (providers != null) {
+ for (InsetsFrameProvider provider : providers) {
+ provider.setInsetsSize(getInsets(height));
+ }
+ }
}
}
+ /**
+ * Get the insets that should be applied to the status bar window given the current status bar
+ * height.
+ *
+ * The status bar window height can sometimes be full-screen (see {@link #applyHeight(State)}.
+ * However, the status bar *insets* should *not* be full-screen, because this would prevent apps
+ * from drawing any content and can cause animations to be cancelled (see b/283958440). Instead,
+ * the status bar insets should always be equal to the space occupied by the actual status bar
+ * content -- setting the insets correctly will prevent window manager from unnecessarily
+ * re-drawing this window and other windows. This method provides the correct insets.
+ */
+ private Insets getInsets(int height) {
+ return Insets.of(0, height, 0, 0);
+ }
+
private void apply(State state) {
if (!mIsAttached) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
index 3e1c13c..c1ac800 100644
--- a/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
+++ b/packages/SystemUI/src/com/android/systemui/stylus/StylusUsiPowerUI.kt
@@ -64,9 +64,9 @@
// These values must only be accessed on the handler.
private var batteryCapacity = 1.0f
private var suppressed = false
- private var inputDeviceId: Int? = null
private var instanceId: InstanceId? = null
-
+ @VisibleForTesting var inputDeviceId: Int? = null
+ private set
@VisibleForTesting var instanceIdSequence = InstanceIdSequence(1 shl 13)
fun init() {
@@ -110,10 +110,10 @@
fun updateBatteryState(deviceId: Int, batteryState: BatteryState) {
handler.post updateBattery@{
+ inputDeviceId = deviceId
if (batteryState.capacity == batteryCapacity || batteryState.capacity <= 0f)
return@updateBattery
- inputDeviceId = deviceId
batteryCapacity = batteryState.capacity
debugLog {
"Updating notification battery state to $batteryCapacity " +
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
index c109eb4..324ef4b 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
@@ -58,6 +58,16 @@
})
}
+ fun logOnSkipToastForInvalidDisplay(packageName: String, token: String, displayId: Int) {
+ log(DEBUG, {
+ str1 = packageName
+ str2 = token
+ int1 = displayId
+ }, {
+ "[$str2] Skip toast for [$str1] scheduled on unavailable display #$int1"
+ })
+ }
+
private inline fun log(
logLevel: LogLevel,
initializer: LogMessage.() -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index ed14c8a..ae8128d 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -32,6 +32,7 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Log;
+import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.widget.ToastPresenter;
@@ -115,8 +116,14 @@
Context context = mContext.createContextAsUser(userHandle, 0);
DisplayManager mDisplayManager = mContext.getSystemService(DisplayManager.class);
- Context displayContext = context.createDisplayContext(
- mDisplayManager.getDisplay(displayId));
+ Display display = mDisplayManager.getDisplay(displayId);
+ if (display == null) {
+ // Display for which this toast was scheduled for is no longer available.
+ mToastLogger.logOnSkipToastForInvalidDisplay(packageName, token.toString(),
+ displayId);
+ return;
+ }
+ Context displayContext = context.createDisplayContext(display);
mToast = mToastFactory.createToast(mContext /* sysuiContext */, text, packageName,
userHandle.getIdentifier(), mOrientation);
diff --git a/packages/SystemUI/src/com/android/systemui/tracing/ProtoTracer.java b/packages/SystemUI/src/com/android/systemui/tracing/ProtoTracer.java
deleted file mode 100644
index b54d156..0000000
--- a/packages/SystemUI/src/com/android/systemui/tracing/ProtoTracer.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.tracing;
-
-import static com.android.systemui.tracing.nano.SystemUiTraceFileProto.MAGIC_NUMBER_H;
-import static com.android.systemui.tracing.nano.SystemUiTraceFileProto.MAGIC_NUMBER_L;
-
-import android.content.Context;
-import android.os.SystemClock;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.shared.tracing.FrameProtoTracer;
-import com.android.systemui.shared.tracing.FrameProtoTracer.ProtoTraceParams;
-import com.android.systemui.shared.tracing.ProtoTraceable;
-import com.android.systemui.tracing.nano.SystemUiTraceEntryProto;
-import com.android.systemui.tracing.nano.SystemUiTraceFileProto;
-import com.android.systemui.tracing.nano.SystemUiTraceProto;
-
-import com.google.protobuf.nano.MessageNano;
-
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Queue;
-
-import javax.inject.Inject;
-
-/**
- * Controller for coordinating winscope proto tracing.
- */
-@SysUISingleton
-public class ProtoTracer implements
- Dumpable,
- ProtoTraceParams<
- MessageNano,
- SystemUiTraceFileProto,
- SystemUiTraceEntryProto,
- SystemUiTraceProto> {
-
- private static final String TAG = "ProtoTracer";
- private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
-
- private final Context mContext;
- private final FrameProtoTracer<MessageNano, SystemUiTraceFileProto, SystemUiTraceEntryProto,
- SystemUiTraceProto> mProtoTracer;
-
- @Inject
- public ProtoTracer(Context context, DumpManager dumpManager) {
- mContext = context;
- mProtoTracer = new FrameProtoTracer<>(this);
- dumpManager.registerDumpable(this);
- }
-
- @Override
- public File getTraceFile() {
- return new File(mContext.getFilesDir(), "sysui_trace.pb");
- }
-
- @Override
- public SystemUiTraceFileProto getEncapsulatingTraceProto() {
- return new SystemUiTraceFileProto();
- }
-
- @Override
- public SystemUiTraceEntryProto updateBufferProto(SystemUiTraceEntryProto reuseObj,
- ArrayList<ProtoTraceable<SystemUiTraceProto>> traceables) {
- SystemUiTraceEntryProto proto = reuseObj != null
- ? reuseObj
- : new SystemUiTraceEntryProto();
- proto.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
- proto.systemUi = proto.systemUi != null ? proto.systemUi : new SystemUiTraceProto();
- for (ProtoTraceable t : traceables) {
- t.writeToProto(proto.systemUi);
- }
- return proto;
- }
-
- @Override
- public byte[] serializeEncapsulatingProto(SystemUiTraceFileProto encapsulatingProto,
- Queue<SystemUiTraceEntryProto> buffer) {
- encapsulatingProto.magicNumber = MAGIC_NUMBER_VALUE;
- encapsulatingProto.entry = buffer.toArray(new SystemUiTraceEntryProto[0]);
- return MessageNano.toByteArray(encapsulatingProto);
- }
-
- @Override
- public byte[] getProtoBytes(MessageNano proto) {
- return MessageNano.toByteArray(proto);
- }
-
- @Override
- public int getProtoSize(MessageNano proto) {
- return proto.getCachedSize();
- }
-
- public void start() {
- mProtoTracer.start();
- }
-
- public void stop() {
- mProtoTracer.stop();
- }
-
- public boolean isEnabled() {
- return mProtoTracer.isEnabled();
- }
-
- public void add(ProtoTraceable<SystemUiTraceProto> traceable) {
- mProtoTracer.add(traceable);
- }
-
- public void remove(ProtoTraceable<SystemUiTraceProto> traceable) {
- mProtoTracer.remove(traceable);
- }
-
- public void scheduleFrameUpdate() {
- mProtoTracer.scheduleFrameUpdate();
- }
-
- public void update() {
- mProtoTracer.update();
- }
-
- @Override
- public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
- pw.println("ProtoTracer:");
- pw.print(" "); pw.println("enabled: " + mProtoTracer.isEnabled());
- pw.print(" "); pw.println("usagePct: " + mProtoTracer.getBufferUsagePct());
- pw.print(" "); pw.println("file: " + getTraceFile());
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
deleted file mode 100644
index d940a6b..0000000
--- a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-syntax = "proto2";
-
-package com.android.systemui.tracing;
-
-option java_multiple_files = true;
-
-message SystemUiTraceProto {
-
- optional EdgeBackGestureHandlerProto edge_back_gesture_handler = 1;
-}
-
-message EdgeBackGestureHandlerProto {
-
- optional bool allow_gesture = 1;
-}
-
-/* represents a file full of system ui trace entries.
- Encoded, it should start with 0x9 0x53 0x59 0x53 0x55 0x49 0x54 0x52 0x43 (.SYSUITRC), such
- that they can be easily identified. */
-message SystemUiTraceFileProto {
-
- /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
- (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
- constants into .proto files. */
- enum MagicNumber {
- INVALID = 0;
- MAGIC_NUMBER_L = 0x55535953; /* SYSU (little-endian ASCII) */
- MAGIC_NUMBER_H = 0x43525449; /* ITRC (little-endian ASCII) */
- }
-
- optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
- repeated SystemUiTraceEntryProto entry = 2;
-}
-
-/* one system ui trace entry. */
-message SystemUiTraceEntryProto {
- /* required: elapsed realtime in nanos since boot of when this entry was logged */
- optional fixed64 elapsed_realtime_nanos = 1;
-
- optional SystemUiTraceProto system_ui = 3;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index d9a8e0c..38226ec 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.NotificationListener;
@@ -138,7 +138,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/src/com/android/systemui/util/wrapper/LottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/util/wrapper/LottieViewWrapper.kt
new file mode 100644
index 0000000..a804923
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/wrapper/LottieViewWrapper.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util.wrapper
+
+import android.content.Context
+import android.util.AttributeSet
+import com.airbnb.lottie.LottieAnimationView
+import com.android.systemui.util.traceSection
+
+/** LottieAnimationView that traces each call to invalidate. */
+open class LottieViewWrapper : LottieAnimationView {
+ constructor(context: Context?) : super(context)
+ constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(
+ context: Context?,
+ attrs: AttributeSet?,
+ defStyleAttr: Int
+ ) : super(context, attrs, defStyleAttr)
+
+ override fun invalidate() {
+ traceSection<Any?>("${this::class} invalidate") {
+ super.invalidate()
+ null
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 9362220..349f368 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -168,6 +168,13 @@
/** Volume dialog slider animation. */
private static final String TYPE_UPDATE = "update";
+ /**
+ * TODO(b/290612381): remove lingering animations or tolerate them
+ * When false, this will cause this class to not listen to animator events and not record jank
+ * events. This should never be false in production code, and only is false for unit tests for
+ * this class. This flag should be true in Scenario/Integration tests.
+ */
+ private final boolean mShouldListenForJank;
private final int mDialogShowAnimationDurationMs;
private final int mDialogHideAnimationDurationMs;
private int mDialogWidth;
@@ -304,6 +311,7 @@
VolumePanelFactory volumePanelFactory,
ActivityStarter activityStarter,
InteractionJankMonitor interactionJankMonitor,
+ boolean shouldListenForJank,
CsdWarningDialog.Factory csdWarningDialogFactory,
DevicePostureController devicePostureController,
Looper looper,
@@ -311,6 +319,8 @@
mContext =
new ContextThemeWrapper(context, R.style.volume_dialog_theme);
mHandler = new H(looper);
+
+ mShouldListenForJank = shouldListenForJank;
mController = volumeDialogController;
mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -1368,7 +1378,10 @@
}
private Animator.AnimatorListener getJankListener(View v, String type, long timeout) {
- return new Animator.AnimatorListener() {
+ if (!mShouldListenForJank) {
+ // TODO(b/290612381): temporary fix to prevent null pointers on leftover JankMonitors
+ return null;
+ } else return new Animator.AnimatorListener() {
@Override
public void onAnimationStart(@NonNull Animator animation) {
if (!v.isAttachedToWindow()) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index aa4ee54..d0edc6e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -72,6 +72,7 @@
volumePanelFactory,
activityStarter,
interactionJankMonitor,
+ true, /* should listen for jank */
csdFactory,
devicePostureController,
Looper.getMainLooper(),
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 5144d19..943e906 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -51,15 +51,11 @@
import com.android.systemui.notetask.NoteTaskInitializer;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.tracing.ProtoTracer;
-import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
-import com.android.wm.shell.nano.WmShellTraceProto;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEventCallback;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
@@ -94,8 +90,7 @@
@SysUISingleton
public final class WMShell implements
CoreStartable,
- CommandQueue.Callbacks,
- ProtoTraceable<SystemUiTraceProto> {
+ CommandQueue.Callbacks {
private static final String TAG = WMShell.class.getName();
private static final int INVALID_SYSUI_STATE_MASK =
SYSUI_STATE_DIALOG_SHOWING
@@ -122,7 +117,6 @@
private final ScreenLifecycle mScreenLifecycle;
private final SysUiState mSysUiState;
private final WakefulnessLifecycle mWakefulnessLifecycle;
- private final ProtoTracer mProtoTracer;
private final UserTracker mUserTracker;
private final DisplayTracker mDisplayTracker;
private final NoteTaskInitializer mNoteTaskInitializer;
@@ -184,7 +178,6 @@
KeyguardUpdateMonitor keyguardUpdateMonitor,
ScreenLifecycle screenLifecycle,
SysUiState sysUiState,
- ProtoTracer protoTracer,
WakefulnessLifecycle wakefulnessLifecycle,
UserTracker userTracker,
DisplayTracker displayTracker,
@@ -203,7 +196,6 @@
mOneHandedOptional = oneHandedOptional;
mDesktopModeOptional = desktopMode;
mWakefulnessLifecycle = wakefulnessLifecycle;
- mProtoTracer = protoTracer;
mUserTracker = userTracker;
mDisplayTracker = displayTracker;
mNoteTaskInitializer = noteTaskInitializer;
@@ -223,7 +215,6 @@
// Subscribe to user changes
mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
- mProtoTracer.add(this);
mCommandQueue.addCallback(this);
mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
@@ -361,12 +352,6 @@
}
@Override
- public void writeToProto(SystemUiTraceProto proto) {
- // Dump to WMShell proto here
- // TODO: Figure out how we want to synchronize while dumping to proto
- }
-
- @Override
public void dump(PrintWriter pw, String[] args) {
// Handle commands if provided
if (mShell.handleCommand(args, pw)) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index 319a02d..d506584 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -33,12 +33,15 @@
import android.app.admin.IKeyguardClient;
import android.content.ComponentName;
import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
+import android.view.Display;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceView;
import android.view.View;
@@ -50,7 +53,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -60,7 +62,6 @@
@RunWithLooper
@RunWith(AndroidTestingRunner.class)
@SmallTest
-@Ignore("b/286245842")
public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private static final int TARGET_USER_ID = KeyguardUpdateMonitor.getCurrentUser();
@@ -79,7 +80,7 @@
private KeyguardSecurityCallback mKeyguardCallback;
@Mock
private KeyguardUpdateMonitor mUpdateMonitor;
- @Mock
+
private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
@Before
@@ -99,6 +100,11 @@
when(mKeyguardClient.queryLocalInterface(anyString())).thenReturn(mKeyguardClient);
when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient);
+ Display display = mContext.getSystemService(DisplayManager.class).getDisplay(
+ Display.DEFAULT_DISPLAY);
+ mSurfacePackage = (new SurfaceControlViewHost(mContext, display,
+ new Binder())).getSurfacePackage();
+
mTestController = new AdminSecondaryLockScreenController.Factory(
mContext, mKeyguardSecurityContainer, mUpdateMonitor, mHandler)
.create(mKeyguardCallback);
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/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index fa32835..677d3ff 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -187,9 +187,7 @@
@Test
public void testLockedOut_verifyPasswordAndUnlock_doesNotEnableViewInput() {
- mKeyguardAbsKeyInputViewController.handleAttemptLockout(
- SystemClock.elapsedRealtime() + 1000);
- mKeyguardAbsKeyInputViewController.verifyPasswordAndUnlock();
+ mKeyguardAbsKeyInputViewController.handleAttemptLockout(SystemClock.elapsedRealtime());
verify(mAbsKeyInputView).setPasswordEntryInputEnabled(false);
verify(mAbsKeyInputView).setPasswordEntryEnabled(false);
verify(mAbsKeyInputView, never()).setPasswordEntryInputEnabled(true);
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/KeyguardPinViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
index 9db267c..d256ee1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinViewControllerTest.kt
@@ -105,6 +105,7 @@
`when`(keyguardPinView.findViewById<View>(R.id.key_enter)).thenReturn(enterButton)
// For posture tests:
`when`(keyguardPinView.buttons).thenReturn(arrayOf())
+ `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
pinViewController =
KeyguardPinViewController(
@@ -167,7 +168,6 @@
@Test
fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsLessThan5() {
`when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true)
- `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
`when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true)
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(3)
`when`(passwordTextView.text).thenReturn("")
@@ -182,7 +182,6 @@
@Test
fun startAppearAnimation_withAutoPinConfirmationFailedPasswordAttemptsMoreThan5() {
`when`(featureFlags.isEnabled(Flags.AUTO_PIN_CONFIRMATION)).thenReturn(true)
- `when`(lockPatternUtils.getPinLength(anyInt())).thenReturn(6)
`when`(lockPatternUtils.isAutoPinConfirmEnabled(anyInt())).thenReturn(true)
`when`(lockPatternUtils.getCurrentFailedPasswordAttempts(anyInt())).thenReturn(6)
`when`(passwordTextView.text).thenReturn("")
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 db58074..d75781a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -163,13 +163,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
@@ -249,10 +251,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));
}
@Test
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..c223c5a 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)
- )
-
- assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
- assertThat(failedAttemptCount).isEqualTo(0)
+ val isThrottled by collectLastValue(underTest.isThrottled)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
+ assertThat(isThrottled).isFalse()
}
@Test
fun authenticate_withIncorrectPin_returnsFalse() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234)
- )
-
- assertThat(underTest.authenticate(listOf(9, 8, 7))).isFalse()
- assertThat(failedAttemptCount).isEqualTo(1)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ assertThat(underTest.authenticate(listOf(9, 8, 7, 6, 5, 4))).isFalse()
}
- @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,243 @@
)
)
.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)
- )
-
- assertThat(underTest.authenticate(listOf(1, 2, 3), tryAutoConfirm = true)).isNull()
- assertThat(failedAttemptCount).isEqualTo(0)
+ val isThrottled by collectLastValue(underTest.isThrottled)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+ assertThat(
+ underTest.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN.toMutableList().apply {
+ removeLast()
+ },
+ tryAutoConfirm = true
+ )
+ )
+ .isNull()
+ assertThat(isThrottled).isFalse()
}
@Test
fun tryAutoConfirm_withAutoConfirmWrongPinCorrectLength_returnsFalseAndDoesNotUnlockDevice() =
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(
+ FakeAuthenticationRepository.DEFAULT_PIN.map { it + 1 },
+ tryAutoConfirm = true
+ )
+ )
+ .isFalse()
+ assertThat(isUnlocked).isFalse()
}
@Test
fun tryAutoConfirm_withAutoConfirmLongerPin_returnsFalseAndDoesNotUnlockDevice() =
testScope.runTest {
- val failedAttemptCount by collectLastValue(underTest.failedAuthenticationAttempts)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = true)
- )
-
- assertThat(underTest.authenticate(listOf(1, 2, 3, 4, 5), tryAutoConfirm = true))
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+ assertThat(
+ underTest.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN + listOf(7),
+ 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(
+ FakeAuthenticationRepository.DEFAULT_PIN,
+ 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)
- )
-
- assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isNull()
- assertThat(failedAttemptCount).isEqualTo(0)
+ val isUnlocked by collectLastValue(underTest.isUnlocked)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(false)
+ assertThat(
+ underTest.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN,
+ tryAutoConfirm = true
+ )
+ )
+ .isNull()
+ 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(FakeAuthenticationRepository.DEFAULT_PIN)
+ 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(FakeAuthenticationRepository.DEFAULT_PIN)).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(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
+ assertThat(isUnlocked).isTrue()
+ assertThat(isThrottled).isFalse()
+ assertThat(throttling).isEqualTo(AuthenticationThrottlingModel())
+ }
+
+ @Test
+ fun hintedPinLength_withoutAutoConfirm_isNull() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(false)
+
+ assertThat(hintedPinLength).isNull()
+ }
+
+ @Test
+ fun hintedPinLength_withAutoConfirmPinTooShort_isNull() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.overrideCredential(
+ buildList {
+ repeat(utils.authenticationRepository.hintedPinLength - 1) { add(it + 1) }
+ }
+ )
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+
+ assertThat(hintedPinLength).isNull()
+ }
+
+ @Test
+ fun hintedPinLength_withAutoConfirmPinAtRightLength_isSameLength() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+ utils.authenticationRepository.overrideCredential(
+ buildList { repeat(utils.authenticationRepository.hintedPinLength) { add(it + 1) } }
+ )
+
+ assertThat(hintedPinLength).isEqualTo(utils.authenticationRepository.hintedPinLength)
+ }
+
+ @Test
+ fun hintedPinLength_withAutoConfirmPinTooLong_isNull() =
+ testScope.runTest {
+ val hintedPinLength by collectLastValue(underTest.hintedPinLength)
+ utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ utils.authenticationRepository.overrideCredential(
+ buildList {
+ repeat(utils.authenticationRepository.hintedPinLength + 1) { add(it + 1) }
+ }
+ )
+ utils.authenticationRepository.setAutoConfirmEnabled(true)
+
+ assertThat(hintedPinLength).isNull()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
index 1482f29..40b5729 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewControllerTest.java
@@ -33,10 +33,10 @@
import androidx.test.filters.SmallTest;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
@@ -61,7 +61,6 @@
private Handler mHandler;
@Mock
private ContentResolver mContentResolver;
- private FakeFeatureFlags mFeatureFlags;
@Mock
private BatteryController mBatteryController;
@@ -74,8 +73,8 @@
when(mBatteryMeterView.getContext()).thenReturn(mContext);
when(mBatteryMeterView.getResources()).thenReturn(mContext.getResources());
- mFeatureFlags = new FakeFeatureFlags();
- mFeatureFlags.set(Flags.BATTERY_SHIELD_ICON, false);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.bool.flag_battery_shield_icon, false);
}
@Test
@@ -134,7 +133,8 @@
@Test
public void shieldFlagDisabled_viewNotified() {
- mFeatureFlags.set(Flags.BATTERY_SHIELD_ICON, false);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.bool.flag_battery_shield_icon, false);
initController();
@@ -143,7 +143,8 @@
@Test
public void shieldFlagEnabled_viewNotified() {
- mFeatureFlags.set(Flags.BATTERY_SHIELD_ICON, true);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.bool.flag_battery_shield_icon, true);
initController();
@@ -153,12 +154,12 @@
private void initController() {
mController = new BatteryMeterViewController(
mBatteryMeterView,
+ StatusBarLocation.HOME,
mUserTracker,
mConfigurationController,
mTunerService,
mHandler,
mContentResolver,
- mFeatureFlags,
mBatteryController
);
}
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/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index d022653..eaa31ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -44,9 +44,6 @@
import android.view.ViewPropertyAnimator
import android.view.WindowInsets
import android.view.WindowManager
-import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
-import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
-import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
import android.view.WindowMetrics
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -55,9 +52,14 @@
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestableContext
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dump.DumpManager
@@ -99,7 +101,7 @@
@SmallTest
@RoboPilotTest
@RunWith(AndroidJUnit4::class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
class SideFpsControllerTest : SysuiTestCase() {
@JvmField @Rule var rule = MockitoJUnit.rule()
@@ -118,6 +120,8 @@
private lateinit var keyguardBouncerRepository: FakeKeyguardBouncerRepository
private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var sideFpsOverlayViewModel: SideFpsOverlayViewModel
+ private val fingerprintRepository = FakeFingerprintPropertyRepository()
private val executor = FakeExecutor(FakeSystemClock())
private val rearDisplayStateRepository = FakeRearDisplayStateRepository()
@@ -159,6 +163,15 @@
executor,
rearDisplayStateRepository
)
+ sideFpsOverlayViewModel =
+ SideFpsOverlayViewModel(context, SideFpsOverlayInteractorImpl(fingerprintRepository))
+
+ fingerprintRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.REAR,
+ sensorLocations = mapOf("" to SensorLocationInternal("", 2500, 0, 0))
+ )
context.addMockSystemService(DisplayManager::class.java, displayManager)
context.addMockSystemService(WindowManager::class.java, windowManager)
@@ -265,6 +278,7 @@
executor,
handler,
alternateBouncerInteractor,
+ { sideFpsOverlayViewModel },
TestCoroutineScope(),
dumpManager
)
@@ -683,106 +697,6 @@
verify(windowManager).removeView(any())
}
- /**
- * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_0,
- * and uses RotateUtils.rotateBounds to map to the correct indicator location given the device
- * rotation. Assuming RotationUtils.rotateBounds works correctly, tests for indicator placement
- * in other rotations have been omitted.
- */
- @Test
- fun verifiesIndicatorPlacementForXAlignedSensor_0() =
- testWithDisplay(
- deviceConfig = DeviceConfig.X_ALIGNED,
- isReverseDefaultRotation = false,
- { rotation = Surface.ROTATION_0 }
- ) {
- sideFpsController.overlayOffsets = sensorLocation
-
- sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
-
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
- executor.runAllReady()
-
- verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
- assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
- assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
- }
-
- /**
- * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_270
- * in reverse default rotation. It then uses RotateUtils.rotateBounds to map to the correct
- * indicator location given the device rotation. Assuming RotationUtils.rotateBounds works
- * correctly, tests for indicator placement in other rotations have been omitted.
- */
- @Test
- fun verifiesIndicatorPlacementForXAlignedSensor_InReverseDefaultRotation_270() =
- testWithDisplay(
- deviceConfig = DeviceConfig.X_ALIGNED,
- isReverseDefaultRotation = true,
- { rotation = Surface.ROTATION_270 }
- ) {
- sideFpsController.overlayOffsets = sensorLocation
-
- sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
-
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
- executor.runAllReady()
-
- verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
- assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
- assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
- }
-
- /**
- * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_0,
- * and uses RotateUtils.rotateBounds to map to the correct indicator location given the device
- * rotation. Assuming RotationUtils.rotateBounds works correctly, tests for indicator placement
- * in other rotations have been omitted.
- */
- @Test
- fun verifiesIndicatorPlacementForYAlignedSensor_0() =
- testWithDisplay(
- deviceConfig = DeviceConfig.Y_ALIGNED,
- isReverseDefaultRotation = false,
- { rotation = Surface.ROTATION_0 }
- ) {
- sideFpsController.overlayOffsets = sensorLocation
-
- sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
-
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
- executor.runAllReady()
-
- verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
- assertThat(overlayViewParamsCaptor.value.x).isEqualTo(displayWidth - boundsWidth)
- assertThat(overlayViewParamsCaptor.value.y).isEqualTo(sensorLocation.sensorLocationY)
- }
-
- /**
- * {@link SideFpsController#updateOverlayParams} calculates indicator placement for ROTATION_270
- * in reverse default rotation. It then uses RotateUtils.rotateBounds to map to the correct
- * indicator location given the device rotation. Assuming RotationUtils.rotateBounds works
- * correctly, tests for indicator placement in other rotations have been omitted.
- */
- @Test
- fun verifiesIndicatorPlacementForYAlignedSensor_InReverseDefaultRotation_270() =
- testWithDisplay(
- deviceConfig = DeviceConfig.Y_ALIGNED,
- isReverseDefaultRotation = true,
- { rotation = Surface.ROTATION_270 }
- ) {
- sideFpsController.overlayOffsets = sensorLocation
-
- sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
-
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
- executor.runAllReady()
-
- verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
- assertThat(overlayViewParamsCaptor.value.x).isEqualTo(displayWidth - boundsWidth)
- assertThat(overlayViewParamsCaptor.value.y).isEqualTo(sensorLocation.sensorLocationY)
- }
-
@Test
fun hasSideFpsSensor_withSensorProps_returnsTrue() = testWithDisplay {
// By default all those tests assume the side fps sensor is available.
@@ -795,51 +709,6 @@
assertThat(fingerprintManager.hasSideFpsSensor()).isFalse()
}
-
- @Test
- fun testLayoutParams_isKeyguardDialogType() =
- testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED) {
- sideFpsController.overlayOffsets = sensorLocation
- sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
- executor.runAllReady()
-
- verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
-
- val lpType = overlayViewParamsCaptor.value.type
-
- assertThat((lpType and TYPE_KEYGUARD_DIALOG) != 0).isTrue()
- }
-
- @Test
- fun testLayoutParams_hasNoMoveAnimationWindowFlag() =
- testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED) {
- sideFpsController.overlayOffsets = sensorLocation
- sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
- executor.runAllReady()
-
- verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
-
- val lpFlags = overlayViewParamsCaptor.value.privateFlags
-
- assertThat((lpFlags and PRIVATE_FLAG_NO_MOVE_ANIMATION) != 0).isTrue()
- }
-
- @Test
- fun testLayoutParams_hasTrustedOverlayWindowFlag() =
- testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED) {
- sideFpsController.overlayOffsets = sensorLocation
- sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
- overlayController.show(SENSOR_ID, REASON_UNKNOWN)
- executor.runAllReady()
-
- verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
-
- val lpFlags = overlayViewParamsCaptor.value.privateFlags
-
- assertThat((lpFlags and PRIVATE_FLAG_TRUSTED_OVERLAY) != 0).isTrue()
- }
}
private fun insetsForSmallNavbar() = insetsWithBottom(60)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
index 239e317..ea25615 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FingerprintRepositoryImplTest.kt
@@ -73,10 +73,15 @@
@Test
fun initializeProperties() =
testScope.runTest {
- val isInitialized = collectLastValue(repository.isInitialized)
+ val sensorId by collectLastValue(repository.sensorId)
+ val strength by collectLastValue(repository.strength)
+ val sensorType by collectLastValue(repository.sensorType)
+ val sensorLocations by collectLastValue(repository.sensorLocations)
- assertDefaultProperties()
- assertThat(isInitialized()).isFalse()
+ // Assert default properties.
+ assertThat(sensorId).isEqualTo(-1)
+ assertThat(strength).isEqualTo(SensorStrength.CONVENIENCE)
+ assertThat(sensorType).isEqualTo(FingerprintSensorType.UNKNOWN)
val fingerprintProps =
listOf(
@@ -115,31 +120,24 @@
fingerprintAuthenticatorsCaptor.value.onAllAuthenticatorsRegistered(fingerprintProps)
- assertThat(repository.sensorId.value).isEqualTo(1)
- assertThat(repository.strength.value).isEqualTo(SensorStrength.STRONG)
- assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.REAR)
+ assertThat(sensorId).isEqualTo(1)
+ assertThat(strength).isEqualTo(SensorStrength.STRONG)
+ assertThat(sensorType).isEqualTo(FingerprintSensorType.REAR)
- assertThat(repository.sensorLocations.value.size).isEqualTo(2)
- assertThat(repository.sensorLocations.value).containsKey("display_id_1")
- with(repository.sensorLocations.value["display_id_1"]!!) {
+ assertThat(sensorLocations?.size).isEqualTo(2)
+ assertThat(sensorLocations).containsKey("display_id_1")
+ with(sensorLocations?.get("display_id_1")!!) {
assertThat(displayId).isEqualTo("display_id_1")
assertThat(sensorLocationX).isEqualTo(100)
assertThat(sensorLocationY).isEqualTo(300)
assertThat(sensorRadius).isEqualTo(20)
}
- assertThat(repository.sensorLocations.value).containsKey("")
- with(repository.sensorLocations.value[""]!!) {
+ assertThat(sensorLocations).containsKey("")
+ with(sensorLocations?.get("")!!) {
assertThat(displayId).isEqualTo("")
assertThat(sensorLocationX).isEqualTo(540)
assertThat(sensorLocationY).isEqualTo(1636)
assertThat(sensorRadius).isEqualTo(130)
}
- assertThat(isInitialized()).isTrue()
}
-
- private fun assertDefaultProperties() {
- assertThat(repository.sensorId.value).isEqualTo(-1)
- assertThat(repository.strength.value).isEqualTo(SensorStrength.CONVENIENCE)
- assertThat(repository.sensorType.value).isEqualTo(FingerprintSensorType.UNKNOWN)
- }
}
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/interactor/SideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
index fd96cf4..896f9b11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsOverlayInteractorTest.kt
@@ -22,6 +22,7 @@
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.coroutines.collectLastValue
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@@ -51,8 +52,9 @@
}
@Test
- fun testGetOverlayOffsets() =
+ fun testGetOverlayoffsets() =
testScope.runTest {
+ // Arrange.
fingerprintRepository.setProperties(
sensorId = 1,
strength = SensorStrength.STRONG,
@@ -76,16 +78,33 @@
)
)
- var offsets = interactor.getOverlayOffsets("display_id_1")
- assertThat(offsets.displayId).isEqualTo("display_id_1")
- assertThat(offsets.sensorLocationX).isEqualTo(100)
- assertThat(offsets.sensorLocationY).isEqualTo(300)
- assertThat(offsets.sensorRadius).isEqualTo(20)
+ // Act.
+ val offsets by collectLastValue(interactor.overlayOffsets)
+ val displayId by collectLastValue(interactor.displayId)
- offsets = interactor.getOverlayOffsets("invalid_display_id")
- assertThat(offsets.displayId).isEqualTo("")
- assertThat(offsets.sensorLocationX).isEqualTo(540)
- assertThat(offsets.sensorLocationY).isEqualTo(1636)
- assertThat(offsets.sensorRadius).isEqualTo(130)
+ // Assert offsets of empty displayId.
+ assertThat(displayId).isEqualTo("")
+ assertThat(offsets?.displayId).isEqualTo("")
+ assertThat(offsets?.sensorLocationX).isEqualTo(540)
+ assertThat(offsets?.sensorLocationY).isEqualTo(1636)
+ assertThat(offsets?.sensorRadius).isEqualTo(130)
+
+ // Offsets should be updated correctly.
+ interactor.changeDisplay("display_id_1")
+ assertThat(displayId).isEqualTo("display_id_1")
+ assertThat(offsets?.displayId).isEqualTo("display_id_1")
+ assertThat(offsets?.sensorLocationX).isEqualTo(100)
+ assertThat(offsets?.sensorLocationY).isEqualTo(300)
+ assertThat(offsets?.sensorRadius).isEqualTo(20)
+
+ // Should return default offset when the displayId is invalid.
+ interactor.changeDisplay("invalid_display_id")
+ assertThat(displayId).isEqualTo("invalid_display_id")
+ assertThat(offsets?.displayId).isEqualTo(SensorLocationInternal.DEFAULT.displayId)
+ assertThat(offsets?.sensorLocationX)
+ .isEqualTo(SensorLocationInternal.DEFAULT.sensorLocationX)
+ assertThat(offsets?.sensorLocationY)
+ .isEqualTo(SensorLocationInternal.DEFAULT.sensorLocationY)
+ assertThat(offsets?.sensorRadius).isEqualTo(SensorLocationInternal.DEFAULT.sensorRadius)
}
}
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/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
new file mode 100644
index 0000000..a859321
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.biometrics.ui.viewmodel
+
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.display.DisplayManagerGlobal
+import android.view.Display
+import android.view.DisplayAdjustments
+import android.view.DisplayInfo
+import android.view.Surface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.SysuiTestableContext
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito
+import org.mockito.junit.MockitoJUnit
+
+private const val DISPLAY_ID = 2
+
+@SmallTest
+@RunWith(JUnit4::class)
+class SideFpsOverlayViewModelTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+ private var testScope: TestScope = TestScope(StandardTestDispatcher())
+
+ private val fingerprintRepository = FakeFingerprintPropertyRepository()
+ private lateinit var interactor: SideFpsOverlayInteractor
+ private lateinit var viewModel: SideFpsOverlayViewModel
+
+ enum class DeviceConfig {
+ X_ALIGNED,
+ Y_ALIGNED,
+ }
+
+ private lateinit var deviceConfig: DeviceConfig
+ private lateinit var indicatorBounds: Rect
+ private lateinit var displayBounds: Rect
+ private lateinit var sensorLocation: SensorLocationInternal
+ private var displayWidth: Int = 0
+ private var displayHeight: Int = 0
+ private var boundsWidth: Int = 0
+ private var boundsHeight: Int = 0
+
+ @Before
+ fun setup() {
+ interactor = SideFpsOverlayInteractorImpl(fingerprintRepository)
+
+ fingerprintRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.REAR,
+ sensorLocations =
+ mapOf(
+ "" to
+ SensorLocationInternal(
+ "" /* displayId */,
+ 540 /* sensorLocationX */,
+ 1636 /* sensorLocationY */,
+ 130 /* sensorRadius */
+ ),
+ "display_id_1" to
+ SensorLocationInternal(
+ "display_id_1" /* displayId */,
+ 100 /* sensorLocationX */,
+ 300 /* sensorLocationY */,
+ 20 /* sensorRadius */
+ )
+ )
+ )
+ }
+
+ @Test
+ fun testOverlayOffsets() =
+ testScope.runTest {
+ viewModel = SideFpsOverlayViewModel(mContext, interactor)
+
+ val interactorOffsets by collectLastValue(interactor.overlayOffsets)
+ val viewModelOffsets by collectLastValue(viewModel.overlayOffsets)
+
+ assertThat(viewModelOffsets).isEqualTo(interactorOffsets)
+ }
+
+ private fun testWithDisplay(
+ deviceConfig: DeviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation: Boolean = false,
+ initInfo: DisplayInfo.() -> Unit = {},
+ block: () -> Unit
+ ) {
+ this.deviceConfig = deviceConfig
+
+ when (deviceConfig) {
+ DeviceConfig.X_ALIGNED -> {
+ displayWidth = 3000
+ displayHeight = 1500
+ sensorLocation = SensorLocationInternal("", 2500, 0, 0)
+ boundsWidth = 200
+ boundsHeight = 100
+ }
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ sensorLocation = SensorLocationInternal("", 0, 300, 0)
+ boundsWidth = 100
+ boundsHeight = 200
+ }
+ }
+
+ indicatorBounds = Rect(0, 0, boundsWidth, boundsHeight)
+ displayBounds = Rect(0, 0, displayWidth, displayHeight)
+
+ val displayInfo = DisplayInfo()
+ displayInfo.initInfo()
+
+ val dmGlobal = Mockito.mock(DisplayManagerGlobal::class.java)
+ val display =
+ Display(
+ dmGlobal,
+ DISPLAY_ID,
+ displayInfo,
+ DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
+ )
+
+ whenever(dmGlobal.getDisplayInfo(ArgumentMatchers.eq(DISPLAY_ID))).thenReturn(displayInfo)
+
+ val sideFpsOverlayViewModelContext =
+ context.createDisplayContext(display) as SysuiTestableContext
+ sideFpsOverlayViewModelContext.orCreateTestableResources.addOverride(
+ com.android.internal.R.bool.config_reverseDefaultRotation,
+ isReverseDefaultRotation
+ )
+ viewModel = SideFpsOverlayViewModel(sideFpsOverlayViewModelContext, interactor)
+
+ block()
+ }
+
+ /**
+ * {@link SideFpsOverlayViewModel#updateSensorBounds} calculates indicator placement for
+ * ROTATION_0, and uses RotateUtils.rotateBounds to map to the correct indicator location given
+ * the device rotation. Assuming RotationUtils.rotateBounds works correctly, tests for indicator
+ * placement in other rotations have been omitted.
+ */
+ @Test
+ fun verifiesIndicatorPlacementForXAlignedSensor_0() =
+ testScope.runTest {
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_0 }
+ ) {
+ viewModel.updateSensorBounds(indicatorBounds, displayBounds, sensorLocation)
+
+ val displayInfo: DisplayInfo = DisplayInfo()
+ context.display!!.getDisplayInfo(displayInfo)
+ assertThat(displayInfo.rotation).isEqualTo(Surface.ROTATION_0)
+
+ assertThat(viewModel.sensorBounds.value).isNotNull()
+ assertThat(viewModel.sensorBounds.value.left)
+ .isEqualTo(sensorLocation.sensorLocationX)
+ assertThat(viewModel.sensorBounds.value.top).isEqualTo(0)
+ }
+ }
+
+ /**
+ * {@link SideFpsOverlayViewModel#updateSensorBounds} calculates indicator placement for
+ * ROTATION_270 in reverse default rotation. It then uses RotateUtils.rotateBounds to map to the
+ * correct indicator location given the device rotation. Assuming RotationUtils.rotateBounds
+ * works correctly, tests for indicator placement in other rotations have been omitted.
+ */
+ @Test
+ fun verifiesIndicatorPlacementForXAlignedSensor_InReverseDefaultRotation_270() =
+ testScope.runTest {
+ testWithDisplay(
+ deviceConfig = DeviceConfig.X_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_270 }
+ ) {
+ viewModel.updateSensorBounds(indicatorBounds, displayBounds, sensorLocation)
+
+ assertThat(viewModel.sensorBounds.value).isNotNull()
+ assertThat(viewModel.sensorBounds.value.left)
+ .isEqualTo(sensorLocation.sensorLocationX)
+ assertThat(viewModel.sensorBounds.value.top).isEqualTo(0)
+ }
+ }
+
+ /**
+ * {@link SideFpsOverlayViewModel#updateSensorBounds} calculates indicator placement for
+ * ROTATION_0, and uses RotateUtils.rotateBounds to map to the correct indicator location given
+ * the device rotation. Assuming RotationUtils.rotateBounds works correctly, tests for indicator
+ * placement in other rotations have been omitted.
+ */
+ @Test
+ fun verifiesIndicatorPlacementForYAlignedSensor_0() =
+ testScope.runTest {
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = false,
+ { rotation = Surface.ROTATION_0 }
+ ) {
+ viewModel.updateSensorBounds(indicatorBounds, displayBounds, sensorLocation)
+
+ assertThat(viewModel.sensorBounds.value).isNotNull()
+ assertThat(viewModel.sensorBounds.value.left).isEqualTo(displayWidth - boundsWidth)
+ assertThat(viewModel.sensorBounds.value.top)
+ .isEqualTo(sensorLocation.sensorLocationY)
+ }
+ }
+
+ /**
+ * {@link SideFpsOverlayViewModel#updateSensorBounds} calculates indicator placement for
+ * ROTATION_270 in reverse default rotation. It then uses RotateUtils.rotateBounds to map to the
+ * correct indicator location given the device rotation. Assuming RotationUtils.rotateBounds
+ * works correctly, tests for indicator placement in other rotations have been omitted.
+ */
+ @Test
+ fun verifiesIndicatorPlacementForYAlignedSensor_InReverseDefaultRotation_270() =
+ testScope.runTest {
+ testWithDisplay(
+ deviceConfig = DeviceConfig.Y_ALIGNED,
+ isReverseDefaultRotation = true,
+ { rotation = Surface.ROTATION_270 }
+ ) {
+ viewModel.updateSensorBounds(indicatorBounds, displayBounds, sensorLocation)
+
+ assertThat(viewModel.sensorBounds.value).isNotNull()
+ assertThat(viewModel.sensorBounds.value.left).isEqualTo(displayWidth - boundsWidth)
+ assertThat(viewModel.sensorBounds.value.top)
+ .isEqualTo(sensorLocation.sensorLocationY)
+ }
+ }
+}
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..6babf04 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)
@@ -91,21 +94,21 @@
assertThat(message).isEqualTo(MESSAGE_ENTER_YOUR_PIN)
// Correct input.
- assertThat(underTest.authenticate(listOf(1, 2, 3, 4))).isTrue()
+ assertThat(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@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()
@@ -115,27 +118,33 @@
assertThat(message).isEmpty()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
- // Wrong 4-digit pin
- assertThat(underTest.authenticate(listOf(1, 2, 3, 5), tryAutoConfirm = true)).isFalse()
+ // Wrong 6-digit pin
+ assertThat(underTest.authenticate(listOf(1, 2, 3, 5, 5, 6), tryAutoConfirm = true))
+ .isFalse()
assertThat(message).isEqualTo(MESSAGE_WRONG_PIN)
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Correct input.
- assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isTrue()
+ assertThat(
+ underTest.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN,
+ tryAutoConfirm = true
+ )
+ )
+ .isTrue()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@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()
@@ -145,7 +154,13 @@
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Correct input.
- assertThat(underTest.authenticate(listOf(1, 2, 3, 4), tryAutoConfirm = true)).isNull()
+ assertThat(
+ underTest.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN,
+ tryAutoConfirm = true
+ )
+ )
+ .isNull()
assertThat(message).isEmpty()
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
}
@@ -153,13 +168,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 +201,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 +221,7 @@
// Wrong input.
assertThat(
underTest.authenticate(
- listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(3, 4))
+ listOf(AuthenticationMethodModel.Pattern.PatternCoordinate(1, 2))
)
)
.isFalse()
@@ -215,21 +232,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 +253,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 +266,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 +284,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(FakeAuthenticationRepository.DEFAULT_PIN)).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(underTest.authenticate(FakeAuthenticationRepository.DEFAULT_PIN)).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..2cc9493 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
@@ -18,6 +18,7 @@
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.coroutines.collectLastValue
import com.android.systemui.scene.SceneTestUtils
@@ -55,17 +56,14 @@
@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:
- underTest.onPinButtonClicked(3)
- underTest.onPinButtonClicked(4)
- underTest.onPinButtonClicked(5)
- underTest.onPinButtonClicked(6)
+ FakeAuthenticationRepository.DEFAULT_PIN.drop(2).forEach { digit ->
+ underTest.onPinButtonClicked(digit)
+ }
underTest.onAuthenticateButtonClicked()
assertThat(animateFailure).isTrue()
@@ -73,10 +71,9 @@
assertThat(animateFailure).isFalse()
// Correct PIN:
- underTest.onPinButtonClicked(1)
- underTest.onPinButtonClicked(2)
- underTest.onPinButtonClicked(3)
- underTest.onPinButtonClicked(4)
+ FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
+ underTest.onPinButtonClicked(digit)
+ }
underTest.onAuthenticateButtonClicked()
assertThat(animateFailure).isFalse()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt
index 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..45d1af7 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
@@ -19,8 +19,8 @@
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.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 +54,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 +74,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 +95,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 +120,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 +146,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 +174,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,18 +202,19 @@
@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)
- underTest.onPinButtonClicked(2)
- underTest.onPinButtonClicked(3)
- underTest.onPinButtonClicked(4)
+ FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
+ underTest.onPinButtonClicked(digit)
+ }
underTest.onAuthenticateButtonClicked()
@@ -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)
@@ -266,10 +275,9 @@
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Bouncer))
// Enter the correct PIN:
- underTest.onPinButtonClicked(1)
- underTest.onPinButtonClicked(2)
- underTest.onPinButtonClicked(3)
- underTest.onPinButtonClicked(4)
+ FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
+ underTest.onPinButtonClicked(digit)
+ }
assertThat(message?.text).isEmpty()
underTest.onAuthenticateButtonClicked()
@@ -280,18 +288,20 @@
@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)
- underTest.onPinButtonClicked(2)
- underTest.onPinButtonClicked(3)
- underTest.onPinButtonClicked(4)
+ FakeAuthenticationRepository.DEFAULT_PIN.forEach { digit ->
+ underTest.onPinButtonClicked(digit)
+ }
assertThat(currentScene).isEqualTo(SceneModel(SceneKey.Gone))
}
@@ -299,20 +309,25 @@
@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)
- underTest.onPinButtonClicked(2)
- underTest.onPinButtonClicked(3)
- underTest.onPinButtonClicked(5) // PIN is now wrong!
+ FakeAuthenticationRepository.DEFAULT_PIN.dropLast(1).forEach { digit ->
+ underTest.onPinButtonClicked(digit)
+ }
+ underTest.onPinButtonClicked(
+ FakeAuthenticationRepository.DEFAULT_PIN.last() + 1
+ ) // PIN is now wrong!
assertThat(entries).hasSize(0)
assertThat(message?.text).isEqualTo(WRONG_PIN)
@@ -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,59 +380,13 @@
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)
}
- @Test
- fun hintedPinLength_withoutAutoConfirm_isNull() =
- testScope.runTest {
- val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234, autoConfirm = false)
- )
-
- assertThat(hintedPinLength).isNull()
- }
-
- @Test
- fun hintedPinLength_withAutoConfirmPinLessThanSixDigits_isNull() =
- testScope.runTest {
- val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(12345, autoConfirm = true)
- )
-
- assertThat(hintedPinLength).isNull()
- }
-
- @Test
- fun hintedPinLength_withAutoConfirmPinExactlySixDigits_isSix() =
- testScope.runTest {
- val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(123456, autoConfirm = true)
- )
-
- assertThat(hintedPinLength).isEqualTo(6)
- }
-
- @Test
- fun hintedPinLength_withAutoConfirmPinMoreThanSixDigits_isNull() =
- testScope.runTest {
- val hintedPinLength by collectLastValue(underTest.hintedPinLength)
- utils.authenticationRepository.setAuthenticationMethod(
- AuthenticationMethodModel.Pin(1234567, autoConfirm = 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/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/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/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
new file mode 100644
index 0000000..45f0a8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.data.repository
+
+import android.media.projection.MediaProjectionInfo
+import android.media.projection.MediaProjectionManager
+import android.os.Binder
+import android.os.IBinder
+import android.os.UserHandle
+import android.view.ContentRecordingSession
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+
+class FakeMediaProjectionManager {
+
+ val mediaProjectionManager = mock<MediaProjectionManager>()
+
+ private val callbacks = mutableListOf<MediaProjectionManager.Callback>()
+
+ init {
+ whenever(mediaProjectionManager.addCallback(any(), any())).thenAnswer {
+ callbacks += it.arguments[0] as MediaProjectionManager.Callback
+ return@thenAnswer Unit
+ }
+ whenever(mediaProjectionManager.removeCallback(any())).thenAnswer {
+ callbacks -= it.arguments[0] as MediaProjectionManager.Callback
+ return@thenAnswer Unit
+ }
+ }
+
+ fun dispatchOnStart(info: MediaProjectionInfo = DEFAULT_INFO) {
+ callbacks.forEach { it.onStart(info) }
+ }
+
+ fun dispatchOnStop(info: MediaProjectionInfo = DEFAULT_INFO) {
+ callbacks.forEach { it.onStop(info) }
+ }
+
+ fun dispatchOnSessionSet(
+ info: MediaProjectionInfo = DEFAULT_INFO,
+ session: ContentRecordingSession?
+ ) {
+ callbacks.forEach { it.onRecordingSessionSet(info, session) }
+ }
+
+ companion object {
+ fun createDisplaySession(): ContentRecordingSession =
+ ContentRecordingSession.createDisplaySession(/* displayToMirror = */ 123)
+ fun createSingleTaskSession(token: IBinder = Binder()): ContentRecordingSession =
+ ContentRecordingSession.createTaskSession(token)
+
+ private const val DEFAULT_PACKAGE_NAME = "com.media.projection.test"
+ private val DEFAULT_USER_HANDLE = UserHandle.getUserHandleForUid(UserHandle.myUserId())
+ private val DEFAULT_INFO = MediaProjectionInfo(DEFAULT_PACKAGE_NAME, DEFAULT_USER_HANDLE)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionRepository.kt
deleted file mode 100644
index c59fd60..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionRepository.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.systemui.mediaprojection.taskswitcher.data.repository
-
-import android.app.TaskInfo
-import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
-
-class FakeMediaProjectionRepository : MediaProjectionRepository {
-
- private val state = MutableStateFlow<MediaProjectionState>(MediaProjectionState.NotProjecting)
-
- fun switchProjectedTask(newTask: TaskInfo) {
- state.value = MediaProjectionState.SingleTask(newTask)
- }
-
- override val mediaProjectionState: Flow<MediaProjectionState> = state.asStateFlow()
-
- fun projectEntireScreen() {
- state.value = MediaProjectionState.EntireScreen
- }
-
- fun stopProjecting() {
- state.value = MediaProjectionState.NotProjecting
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
deleted file mode 100644
index 593e389..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeTasksRepository.kt
+++ /dev/null
@@ -1,68 +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.mediaprojection.taskswitcher.data.repository
-
-import android.app.ActivityManager.RunningTaskInfo
-import android.content.Intent
-import android.os.IBinder
-import android.window.IWindowContainerToken
-import android.window.WindowContainerToken
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
-
-class FakeTasksRepository : TasksRepository {
-
- private val _foregroundTask = MutableStateFlow(DEFAULT_TASK)
-
- override val foregroundTask: Flow<RunningTaskInfo> = _foregroundTask.asStateFlow()
-
- private val runningTasks = mutableListOf(DEFAULT_TASK)
-
- override suspend fun findRunningTaskFromWindowContainerToken(
- windowContainerToken: IBinder
- ): RunningTaskInfo? = runningTasks.firstOrNull { it.token.asBinder() == windowContainerToken }
-
- fun addRunningTask(task: RunningTaskInfo) {
- runningTasks.add(task)
- }
-
- fun moveTaskToForeground(task: RunningTaskInfo) {
- _foregroundTask.value = task
- }
-
- companion object {
- val DEFAULT_TASK = createTask(taskId = -1)
- val LAUNCHER_INTENT: Intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
-
- fun createTask(
- taskId: Int,
- token: WindowContainerToken = createToken(),
- baseIntent: Intent = Intent()
- ) =
- RunningTaskInfo().apply {
- this.taskId = taskId
- this.token = token
- this.baseIntent = baseIntent
- }
-
- fun createToken(): WindowContainerToken {
- val realToken = object : IWindowContainerToken.Stub() {}
- return WindowContainerToken(realToken)
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
index 2b07465..3a74c72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -16,27 +16,22 @@
package com.android.systemui.mediaprojection.taskswitcher.data.repository
-import android.media.projection.MediaProjectionInfo
-import android.media.projection.MediaProjectionManager
import android.os.Binder
import android.os.Handler
-import android.os.UserHandle
import android.testing.AndroidTestingRunner
import android.view.ContentRecordingSession
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createToken
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,29 +40,26 @@
@SmallTest
class MediaProjectionManagerRepositoryTest : SysuiTestCase() {
- private val mediaProjectionManager = mock<MediaProjectionManager>()
-
private val dispatcher = StandardTestDispatcher()
private val testScope = TestScope(dispatcher)
- private val tasksRepo = FakeTasksRepository()
- private lateinit var callback: MediaProjectionManager.Callback
- private lateinit var repo: MediaProjectionManagerRepository
+ private val fakeMediaProjectionManager = FakeMediaProjectionManager()
+ private val fakeActivityTaskManager = FakeActivityTaskManager()
- @Before
- fun setUp() {
- whenever(mediaProjectionManager.addCallback(any(), any())).thenAnswer {
- callback = it.arguments[0] as MediaProjectionManager.Callback
- return@thenAnswer Unit
- }
- repo =
- MediaProjectionManagerRepository(
- mediaProjectionManager = mediaProjectionManager,
- handler = Handler.getMain(),
- applicationScope = testScope.backgroundScope,
- tasksRepository = tasksRepo
- )
- }
+ private val tasksRepo =
+ ActivityTaskManagerTasksRepository(
+ activityTaskManager = fakeActivityTaskManager.activityTaskManager,
+ applicationScope = testScope.backgroundScope,
+ backgroundDispatcher = dispatcher
+ )
+
+ private val repo =
+ MediaProjectionManagerRepository(
+ mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
+ handler = Handler.getMain(),
+ applicationScope = testScope.backgroundScope,
+ tasksRepository = tasksRepo
+ )
@Test
fun mediaProjectionState_onStart_emitsNotProjecting() =
@@ -75,7 +67,7 @@
val state by collectLastValue(repo.mediaProjectionState)
runCurrent()
- callback.onStart(TEST_MEDIA_INFO)
+ fakeMediaProjectionManager.dispatchOnStart()
assertThat(state).isEqualTo(MediaProjectionState.NotProjecting)
}
@@ -86,7 +78,7 @@
val state by collectLastValue(repo.mediaProjectionState)
runCurrent()
- callback.onStop(TEST_MEDIA_INFO)
+ fakeMediaProjectionManager.dispatchOnStop()
assertThat(state).isEqualTo(MediaProjectionState.NotProjecting)
}
@@ -97,7 +89,7 @@
val state by collectLastValue(repo.mediaProjectionState)
runCurrent()
- callback.onRecordingSessionSet(TEST_MEDIA_INFO, /* session= */ null)
+ fakeMediaProjectionManager.dispatchOnSessionSet(session = null)
assertThat(state).isEqualTo(MediaProjectionState.NotProjecting)
}
@@ -108,8 +100,9 @@
val state by collectLastValue(repo.mediaProjectionState)
runCurrent()
- val session = ContentRecordingSession.createDisplaySession(/* displayToMirror= */ 123)
- callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = ContentRecordingSession.createDisplaySession(/* displayToMirror= */ 123)
+ )
assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
}
@@ -120,9 +113,10 @@
val state by collectLastValue(repo.mediaProjectionState)
runCurrent()
- val session =
- ContentRecordingSession.createTaskSession(/* taskWindowContainerToken= */ null)
- callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session =
+ ContentRecordingSession.createTaskSession(/* taskWindowContainerToken= */ null)
+ )
assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
}
@@ -134,8 +128,9 @@
runCurrent()
val taskWindowContainerToken = Binder()
- val session = ContentRecordingSession.createTaskSession(taskWindowContainerToken)
- callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = ContentRecordingSession.createTaskSession(taskWindowContainerToken)
+ )
assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
}
@@ -143,20 +138,16 @@
@Test
fun mediaProjectionState_sessionSet_taskWithToken_matchingRunningTask_emitsSingleTask() =
testScope.runTest {
- val token = FakeTasksRepository.createToken()
- val task = FakeTasksRepository.createTask(taskId = 1, token = token)
- tasksRepo.addRunningTask(task)
+ val token = createToken()
+ val task = createTask(taskId = 1, token = token)
+ fakeActivityTaskManager.addRunningTasks(task)
val state by collectLastValue(repo.mediaProjectionState)
runCurrent()
- val session = ContentRecordingSession.createTaskSession(token.asBinder())
- callback.onRecordingSessionSet(TEST_MEDIA_INFO, session)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = ContentRecordingSession.createTaskSession(token.asBinder())
+ )
assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
}
-
- companion object {
- val TEST_MEDIA_INFO =
- MediaProjectionInfo(/* packageName= */ "com.test.package", UserHandle.CURRENT)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
index 112950b..b2ebe1bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.mediaprojection.taskswitcher.domain.interactor
import android.content.Intent
+import android.os.Handler
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -24,7 +25,9 @@
import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager
import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
-import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager.Companion.createSingleTaskSession
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionManagerRepository
import com.android.systemui.mediaprojection.taskswitcher.domain.model.TaskSwitchState
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -43,7 +46,8 @@
private val testScope = TestScope(dispatcher)
private val fakeActivityTaskManager = FakeActivityTaskManager()
- private val mediaRepo = FakeMediaProjectionRepository()
+ private val fakeMediaProjectionManager = FakeMediaProjectionManager()
+
private val tasksRepo =
ActivityTaskManagerTasksRepository(
activityTaskManager = fakeActivityTaskManager.activityTaskManager,
@@ -51,15 +55,26 @@
backgroundDispatcher = dispatcher
)
+ private val mediaRepo =
+ MediaProjectionManagerRepository(
+ mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
+ handler = Handler.getMain(),
+ applicationScope = testScope.backgroundScope,
+ tasksRepository = tasksRepo,
+ )
+
private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
@Test
fun taskSwitchChanges_notProjecting_foregroundTaskChange_emitsNotProjectingTask() =
testScope.runTest {
- mediaRepo.stopProjecting()
+ val backgroundTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1)
val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
- fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 1))
+ fakeActivityTaskManager.addRunningTasks(backgroundTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnStop()
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(taskSwitchState).isEqualTo(TaskSwitchState.NotProjectingTask)
}
@@ -67,10 +82,15 @@
@Test
fun taskSwitchChanges_projectingScreen_foregroundTaskChange_emitsNotProjectingTask() =
testScope.runTest {
- mediaRepo.projectEntireScreen()
+ val backgroundTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1)
val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
- fakeActivityTaskManager.moveTaskToForeground(createTask(taskId = 1))
+ fakeActivityTaskManager.addRunningTasks(backgroundTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = FakeMediaProjectionManager.createDisplaySession()
+ )
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(taskSwitchState).isEqualTo(TaskSwitchState.NotProjectingTask)
}
@@ -80,9 +100,12 @@
testScope.runTest {
val projectedTask = createTask(taskId = 0)
val foregroundTask = createTask(taskId = 1)
- mediaRepo.switchProjectedTask(projectedTask)
val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(token = projectedTask.token.asBinder())
+ )
fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(taskSwitchState)
@@ -99,9 +122,12 @@
testScope.runTest {
val projectedTask = createTask(taskId = 0)
val foregroundTask = createTask(taskId = 1, baseIntent = LAUNCHER_INTENT)
- mediaRepo.switchProjectedTask(projectedTask)
val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(projectedTask.token.asBinder())
+ )
fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
@@ -111,11 +137,13 @@
fun taskSwitchChanges_projectingTask_foregroundTaskSame_emitsTaskUnchanged() =
testScope.runTest {
val projectedTask = createTask(taskId = 0)
- val foregroundTask = createTask(taskId = 0)
- mediaRepo.switchProjectedTask(projectedTask)
val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
- fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+ fakeActivityTaskManager.addRunningTasks(projectedTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(projectedTask.token.asBinder())
+ )
+ fakeActivityTaskManager.moveTaskToForeground(projectedTask)
assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
new file mode 100644
index 0000000..b396caf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.taskswitcher.ui
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.os.Handler
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionManagerRepository
+import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
+import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertEquals
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+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.ArgumentCaptor
+import org.mockito.Mockito.verify
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class TaskSwitcherNotificationCoordinatorTest : SysuiTestCase() {
+
+ private val notificationManager: NotificationManager = mock()
+
+ private val dispatcher = UnconfinedTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+
+ private val fakeActivityTaskManager = FakeActivityTaskManager()
+ private val fakeMediaProjectionManager = FakeMediaProjectionManager()
+
+ private val tasksRepo =
+ ActivityTaskManagerTasksRepository(
+ activityTaskManager = fakeActivityTaskManager.activityTaskManager,
+ applicationScope = testScope.backgroundScope,
+ backgroundDispatcher = dispatcher
+ )
+
+ private val mediaRepo =
+ MediaProjectionManagerRepository(
+ mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
+ handler = Handler.getMain(),
+ applicationScope = testScope.backgroundScope,
+ tasksRepository = tasksRepo,
+ )
+
+ private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
+ private val viewModel = TaskSwitcherNotificationViewModel(interactor)
+
+ private val coordinator =
+ TaskSwitcherNotificationCoordinator(
+ context,
+ notificationManager,
+ testScope.backgroundScope,
+ dispatcher,
+ viewModel
+ )
+
+ @Before
+ fun setup() {
+ coordinator.start()
+ }
+
+ @Test
+ fun showNotification() {
+ testScope.runTest {
+ switchTask()
+
+ val notification = ArgumentCaptor.forClass(Notification::class.java)
+ verify(notificationManager).notify(any(), any(), notification.capture())
+ assertNotification(notification)
+ }
+ }
+
+ @Test
+ fun hideNotification() {
+ testScope.runTest {
+ fakeMediaProjectionManager.dispatchOnStop()
+
+ verify(notificationManager).cancel(any())
+ }
+ }
+
+ @Test
+ fun notificationIdIsConsistent() {
+ testScope.runTest {
+ fakeMediaProjectionManager.dispatchOnStop()
+ val idCancel = argumentCaptor<Int>()
+ verify(notificationManager).cancel(idCancel.capture())
+
+ switchTask()
+ val idNotify = argumentCaptor<Int>()
+ verify(notificationManager).notify(any(), idNotify.capture(), any())
+
+ assertEquals(idCancel.value, idNotify.value)
+ }
+ }
+
+ private fun switchTask() {
+ val projectedTask = FakeActivityTaskManager.createTask(taskId = 1)
+ val foregroundTask = FakeActivityTaskManager.createTask(taskId = 2)
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session =
+ FakeMediaProjectionManager.createSingleTaskSession(projectedTask.token.asBinder())
+ )
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+ }
+
+ private fun assertNotification(notification: ArgumentCaptor<Notification>) {
+ val text = notification.value.extras.getCharSequence(Notification.EXTRA_TEXT)
+ assertEquals(context.getString(R.string.media_projection_task_switcher_text), text)
+
+ val actions = notification.value.actions
+ assertThat(actions).hasLength(2)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
index ea44fb3..7d38de4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel
import android.content.Intent
+import android.os.Handler
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -24,7 +25,10 @@
import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager
import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
-import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionRepository
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager.Companion.createDisplaySession
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager.Companion.createSingleTaskSession
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionManagerRepository
import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState
import com.google.common.truth.Truth.assertThat
@@ -44,13 +48,23 @@
private val testScope = TestScope(dispatcher)
private val fakeActivityTaskManager = FakeActivityTaskManager()
- private val mediaRepo = FakeMediaProjectionRepository()
+ private val fakeMediaProjectionManager = FakeMediaProjectionManager()
+
private val tasksRepo =
ActivityTaskManagerTasksRepository(
activityTaskManager = fakeActivityTaskManager.activityTaskManager,
applicationScope = testScope.backgroundScope,
backgroundDispatcher = dispatcher
)
+
+ private val mediaRepo =
+ MediaProjectionManagerRepository(
+ mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
+ handler = Handler.getMain(),
+ applicationScope = testScope.backgroundScope,
+ tasksRepository = tasksRepo,
+ )
+
private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
private val viewModel = TaskSwitcherNotificationViewModel(interactor)
@@ -58,19 +72,23 @@
@Test
fun uiState_notProjecting_emitsNotShowing() =
testScope.runTest {
- mediaRepo.stopProjecting()
val uiState by collectLastValue(viewModel.uiState)
+ fakeMediaProjectionManager.dispatchOnStop()
+
assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
}
@Test
fun uiState_notProjecting_foregroundTaskChanged_emitsNotShowing() =
testScope.runTest {
- mediaRepo.stopProjecting()
+ val backgroundTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1)
val uiState by collectLastValue(viewModel.uiState)
- mediaRepo.switchProjectedTask(createTask(taskId = 1))
+ fakeActivityTaskManager.addRunningTasks(backgroundTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnStop()
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
}
@@ -78,19 +96,23 @@
@Test
fun uiState_projectingEntireScreen_emitsNotShowing() =
testScope.runTest {
- mediaRepo.projectEntireScreen()
val uiState by collectLastValue(viewModel.uiState)
+ fakeMediaProjectionManager.dispatchOnSessionSet(session = createDisplaySession())
+
assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
}
@Test
fun uiState_projectingEntireScreen_foregroundTaskChanged_emitsNotShowing() =
testScope.runTest {
- mediaRepo.projectEntireScreen()
+ val backgroundTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1)
val uiState by collectLastValue(viewModel.uiState)
- mediaRepo.switchProjectedTask(createTask(taskId = 1))
+ fakeActivityTaskManager.addRunningTasks(backgroundTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(session = createDisplaySession())
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
}
@@ -100,9 +122,12 @@
testScope.runTest {
val projectedTask = createTask(taskId = 1)
val foregroundTask = createTask(taskId = 2)
- mediaRepo.switchProjectedTask(projectedTask)
val uiState by collectLastValue(viewModel.uiState)
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(projectedTask.token.asBinder())
+ )
fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(uiState)
@@ -113,9 +138,12 @@
fun uiState_projectingTask_foregroundTaskChanged_same_emitsNotShowing() =
testScope.runTest {
val projectedTask = createTask(taskId = 1)
- mediaRepo.switchProjectedTask(projectedTask)
val uiState by collectLastValue(viewModel.uiState)
+ fakeActivityTaskManager.addRunningTasks(projectedTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(projectedTask.token.asBinder())
+ )
fakeActivityTaskManager.moveTaskToForeground(projectedTask)
assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
@@ -126,9 +154,12 @@
testScope.runTest {
val projectedTask = createTask(taskId = 1)
val foregroundTask = createTask(taskId = 2, baseIntent = LAUNCHER_INTENT)
- mediaRepo.switchProjectedTask(projectedTask)
val uiState by collectLastValue(viewModel.uiState)
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(projectedTask.token.asBinder())
+ )
fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
index 023ed06..45bb931 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/domain/interactor/PowerInteractorTest.kt
@@ -21,6 +21,10 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.FakePowerRepository
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
@@ -44,6 +48,7 @@
private lateinit var underTest: PowerInteractor
private lateinit var repository: FakePowerRepository
+ private val keyguardRepository = FakeKeyguardRepository()
@Mock private lateinit var falsingCollector: FalsingCollector
@Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
@Mock private lateinit var statusBarStateController: StatusBarStateController
@@ -59,6 +64,7 @@
underTest =
PowerInteractor(
repository,
+ keyguardRepository,
falsingCollector,
screenOffAnimationController,
statusBarStateController,
@@ -125,6 +131,57 @@
verify(falsingCollector).onScreenOnFromTouch()
}
+ @Test
+ fun wakeUpForFullScreenIntent_notGoingToSleepAndNotDozing_notWoken() {
+ keyguardRepository.setWakefulnessModel(
+ WakefulnessModel(
+ state = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.OTHER,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ )
+ whenever(statusBarStateController.isDozing).thenReturn(false)
+
+ underTest.wakeUpForFullScreenIntent()
+
+ assertThat(repository.lastWakeWhy).isNull()
+ assertThat(repository.lastWakeReason).isNull()
+ }
+
+ @Test
+ fun wakeUpForFullScreenIntent_startingToSleep_woken() {
+ keyguardRepository.setWakefulnessModel(
+ WakefulnessModel(
+ state = WakefulnessState.STARTING_TO_SLEEP,
+ lastWakeReason = WakeSleepReason.OTHER,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ )
+ whenever(statusBarStateController.isDozing).thenReturn(false)
+
+ underTest.wakeUpForFullScreenIntent()
+
+ assertThat(repository.lastWakeWhy).isNotNull()
+ assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_APPLICATION)
+ }
+
+ @Test
+ fun wakeUpForFullScreenIntent_dozing_woken() {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+ keyguardRepository.setWakefulnessModel(
+ WakefulnessModel(
+ state = WakefulnessState.AWAKE,
+ lastWakeReason = WakeSleepReason.OTHER,
+ lastSleepReason = WakeSleepReason.OTHER,
+ )
+ )
+
+ underTest.wakeUpForFullScreenIntent()
+
+ assertThat(repository.lastWakeWhy).isNotNull()
+ assertThat(repository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_APPLICATION)
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
}
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..3e9ddcb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SystemUiDefaultSceneContainerStartableTest.kt
@@ -0,0 +1,402 @@
+/*
+ * 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.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
+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 keyguardRepository = utils.keyguardRepository()
+ private val keyguardInteractor =
+ utils.keyguardInteractor(
+ repository = keyguardRepository,
+ )
+
+ private val underTest =
+ SystemUiDefaultSceneContainerStartable(
+ applicationScope = testScope.backgroundScope,
+ sceneInteractor = sceneInteractor,
+ authenticationInteractor = authenticationInteractor,
+ keyguardInteractor = keyguardInteractor,
+ 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)
+ }
+
+ @Test
+ fun switchToGoneWhenDeviceSleepsUnlocked_featureEnabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = true,
+ isDeviceUnlocked = true,
+ initialSceneKey = SceneKey.Shade,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+ underTest.start()
+
+ keyguardRepository.setWakefulnessModel(ASLEEP)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Gone)
+ }
+
+ @Test
+ fun switchToGoneWhenDeviceSleepsUnlocked_featureDisabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = false,
+ isDeviceUnlocked = true,
+ initialSceneKey = SceneKey.Shade,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+ underTest.start()
+
+ keyguardRepository.setWakefulnessModel(ASLEEP)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+ }
+
+ @Test
+ fun switchToLockscreenWhenDeviceSleepsLocked_featureEnabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = true,
+ isDeviceUnlocked = false,
+ initialSceneKey = SceneKey.Shade,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+ underTest.start()
+
+ keyguardRepository.setWakefulnessModel(ASLEEP)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+ }
+
+ @Test
+ fun switchToLockscreenWhenDeviceSleepsLocked_featureDisabled() =
+ testScope.runTest {
+ val currentSceneKey by
+ collectLastValue(
+ sceneInteractor.currentScene(SceneContainerNames.SYSTEM_UI_DEFAULT).map {
+ it.key
+ }
+ )
+ prepareState(
+ isFeatureEnabled = false,
+ isDeviceUnlocked = false,
+ initialSceneKey = SceneKey.Shade,
+ )
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+ underTest.start()
+
+ keyguardRepository.setWakefulnessModel(ASLEEP)
+
+ assertThat(currentSceneKey).isEqualTo(SceneKey.Shade)
+ }
+
+ 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))
+ }
+ }
+
+ companion object {
+ private val ASLEEP =
+ WakefulnessModel(
+ state = WakefulnessState.ASLEEP,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.POWER_BUTTON
+ )
+ }
+}
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 16751c9..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
@@ -16,12 +16,14 @@
package com.android.systemui.settings.brightness
+import android.content.Intent
import android.graphics.Rect
import android.os.Handler
import android.testing.AndroidTestingRunner
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 com.android.systemui.R
@@ -29,15 +31,20 @@
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
@@ -48,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)
@@ -64,7 +74,8 @@
displayTracker,
brightnessSliderControllerFactory,
mainExecutor,
- backgroundHandler
+ backgroundHandler,
+ accessibilityMgr
)
},
/* initialTouchMode= */ false,
@@ -77,8 +88,6 @@
`when`(brightnessSliderControllerFactory.create(any(), any()))
.thenReturn(brightnessSliderController)
`when`(brightnessSliderController.rootView).thenReturn(View(context))
-
- activityRule.launchActivity(null)
}
@After
@@ -88,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
@@ -104,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/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index a4fab1d..77a22ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -28,6 +28,7 @@
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.data.repository.FakePowerRepository
@@ -89,6 +90,7 @@
dockManager,
PowerInteractor(
powerRepository,
+ FakeKeyguardRepository(),
falsingCollector,
screenOffAnimationController,
statusBarStateController,
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/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index f542ab0..bf25f29 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -29,6 +29,7 @@
import android.view.View
import android.view.ViewPropertyAnimator
import android.view.WindowInsets
+import android.widget.LinearLayout
import android.widget.TextView
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.constraintlayout.widget.ConstraintSet
@@ -127,6 +128,7 @@
var viewVisibility = View.GONE
var viewAlpha = 1f
+ private val systemIcons = LinearLayout(context)
private lateinit var shadeHeaderController: ShadeHeaderController
private lateinit var carrierIconSlots: List<String>
private val configurationController = FakeConfigurationController()
@@ -146,6 +148,7 @@
.thenReturn(batteryMeterView)
whenever<StatusIconContainer>(view.findViewById(R.id.statusIcons)).thenReturn(statusIcons)
+ whenever<View>(view.findViewById(R.id.shade_header_system_icons)).thenReturn(systemIcons)
viewContext = Mockito.spy(context)
whenever(view.context).thenReturn(viewContext)
@@ -451,6 +454,17 @@
}
@Test
+ fun testLargeScreenActive_collapseActionRun_onSystemIconsClick() {
+ shadeHeaderController.largeScreenActive = true
+ var wasRun = false
+ shadeHeaderController.shadeCollapseAction = Runnable { wasRun = true }
+
+ systemIcons.performClick()
+
+ assertThat(wasRun).isTrue()
+ }
+
+ @Test
fun testShadeExpandedFraction() {
// View needs to be visible for this to actually take effect
shadeHeaderController.qsVisible = true
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 b1f5dde..8cf005dc 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,73 +57,28 @@
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.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;
@@ -137,205 +89,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/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index ff2f106..4a2518a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -101,16 +101,18 @@
@Mock lateinit var activityStarter: ActivityStarter
@Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
private val disableFlagsRepository = FakeDisableFlagsRepository()
+ private val keyguardRepository = FakeKeyguardRepository()
private val shadeInteractor = ShadeInteractor(
testScope.backgroundScope,
disableFlagsRepository,
- keyguardRepository = FakeKeyguardRepository(),
+ keyguardRepository,
userSetupRepository = FakeUserSetupRepository(),
deviceProvisionedController = mock(),
userInteractor = mock(),
)
private val powerInteractor = PowerInteractor(
FakePowerRepository(),
+ keyguardRepository,
FalsingCollectorFake(),
screenOffAnimationController = mock(),
statusBarStateController = mock(),
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/RoundableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
index 89faa239..a56fb2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/RoundableTest.kt
@@ -3,7 +3,11 @@
import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
@@ -15,8 +19,9 @@
@SmallTest
@RunWith(JUnit4::class)
class RoundableTest : SysuiTestCase() {
- val targetView: View = mock()
- val roundable = FakeRoundable(targetView)
+ private val targetView: View = mock()
+ private val featureFlags = FakeFeatureFlags()
+ private val roundable = FakeRoundable(targetView = targetView, featureFlags = featureFlags)
@Test
fun defaultConfig_shouldNotHaveRoundedCorner() {
@@ -144,16 +149,62 @@
assertEquals(0.2f, roundable.roundableState.bottomRoundness)
}
+ @Test
+ fun getCornerRadii_radius_maxed_to_height() {
+ whenever(targetView.height).thenReturn(10)
+ featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true)
+ roundable.requestRoundness(1f, 1f, SOURCE1)
+
+ assertCornerRadiiEquals(5f, 5f)
+ }
+
+ @Test
+ fun getCornerRadii_topRadius_maxed_to_height() {
+ whenever(targetView.height).thenReturn(5)
+ featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true)
+ roundable.requestRoundness(1f, 0f, SOURCE1)
+
+ assertCornerRadiiEquals(5f, 0f)
+ }
+
+ @Test
+ fun getCornerRadii_bottomRadius_maxed_to_height() {
+ whenever(targetView.height).thenReturn(5)
+ featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true)
+ roundable.requestRoundness(0f, 1f, SOURCE1)
+
+ assertCornerRadiiEquals(0f, 5f)
+ }
+
+ @Test
+ fun getCornerRadii_radii_kept() {
+ whenever(targetView.height).thenReturn(100)
+ featureFlags.set(Flags.IMPROVED_HUN_ANIMATIONS, true)
+ roundable.requestRoundness(1f, 1f, SOURCE1)
+
+ assertCornerRadiiEquals(MAX_RADIUS, MAX_RADIUS)
+ }
+
+ private fun assertCornerRadiiEquals(top: Float, bottom: Float) {
+ assertEquals("topCornerRadius", top, roundable.topCornerRadius)
+ assertEquals("bottomCornerRadius", bottom, roundable.bottomCornerRadius)
+ }
+
class FakeRoundable(
targetView: View,
radius: Float = MAX_RADIUS,
+ featureFlags: FeatureFlags
) : Roundable {
override val roundableState =
RoundableState(
targetView = targetView,
roundable = this,
maxRadius = radius,
+ featureFlags = featureFlags
)
+
+ override val clipHeight: Int
+ get() = roundableState.targetView.height
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index d3e5816..daa45db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -426,23 +426,8 @@
}
@Test
- public void testShouldHeadsUp_oldWhen_flagDisabled() throws Exception {
- ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(false);
-
- NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
- entry.getSbn().getNotification().when = makeWhenHoursAgo(25);
-
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
-
- verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
- verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
- }
-
- @Test
public void testShouldHeadsUp_oldWhen_whenNow() throws Exception {
ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -455,7 +440,6 @@
@Test
public void testShouldHeadsUp_oldWhen_whenRecent() throws Exception {
ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
entry.getSbn().getNotification().when = makeWhenHoursAgo(13);
@@ -469,7 +453,6 @@
@Test
public void testShouldHeadsUp_oldWhen_whenZero() throws Exception {
ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
entry.getSbn().getNotification().when = 0L;
@@ -484,7 +467,6 @@
@Test
public void testShouldHeadsUp_oldWhen_whenNegative() throws Exception {
ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
entry.getSbn().getNotification().when = -1L;
@@ -498,7 +480,6 @@
@Test
public void testShouldHeadsUp_oldWhen_hasFullScreenIntent() throws Exception {
ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
long when = makeWhenHoursAgo(25);
NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silent= */ false);
@@ -514,7 +495,6 @@
@Test
public void testShouldHeadsUp_oldWhen_isForegroundService() throws Exception {
ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
long when = makeWhenHoursAgo(25);
NotificationEntry entry = createFgsNotification(IMPORTANCE_HIGH);
@@ -530,7 +510,6 @@
@Test
public void testShouldNotHeadsUp_oldWhen() throws Exception {
ensureStateForHeadsUpWhenAwake();
- when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
long when = makeWhenHoursAgo(25);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
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/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
index a87dd2d..8881f42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/domain/interactor/NotificationShelfInteractorTest.kt
@@ -58,6 +58,7 @@
private val powerInteractor =
PowerInteractor(
powerRepository,
+ keyguardRepository,
FalsingCollectorFake(),
screenOffAnimationController,
statusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index 7ae1502..6221f3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -69,6 +69,7 @@
private val powerInteractor by lazy {
PowerInteractor(
powerRepository,
+ keyguardRepository,
FalsingCollectorFake(),
screenOffAnimationController,
statusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index 442ba09..5e0e140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -95,6 +95,7 @@
Lazy { notifShadeWindowController },
activityLaunchAnimator,
context,
+ DISPLAY_ID,
lockScreenUserManager,
statusBarWindowController,
wakefulnessLifecycle,
@@ -274,4 +275,8 @@
mainExecutor.runAllReady()
verify(statusBarStateController).setLeaveOpenOnKeyguardHide(true)
}
+
+ private companion object {
+ private const val DISPLAY_ID = 0
+ }
}
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/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index 6a4b3c5..df3c1e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -22,7 +22,6 @@
import static junit.framework.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -45,8 +44,6 @@
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -65,20 +62,13 @@
private static final GradientColors COLORS_LIGHT = makeColors(Color.WHITE);
private static final GradientColors COLORS_DARK = makeColors(Color.BLACK);
- private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
private LightBarTransitionsController mLightBarTransitionsController;
private LightBarTransitionsController mNavBarController;
private SysuiDarkIconDispatcher mStatusBarIconController;
private LightBarController mLightBarController;
- /** Allow testing with NEW_LIGHT_BAR_LOGIC flag in different states */
- protected boolean testNewLightBarLogic() {
- return false;
- }
-
@Before
public void setup() {
- mFeatureFlags.set(Flags.NEW_LIGHT_BAR_LOGIC, testNewLightBarLogic());
mStatusBarIconController = mock(SysuiDarkIconDispatcher.class);
mNavBarController = mock(LightBarTransitionsController.class);
when(mNavBarController.supportsIconTintForNavMode(anyInt())).thenReturn(true);
@@ -90,7 +80,6 @@
mStatusBarIconController,
mock(BatteryController.class),
mock(NavigationModeController.class),
- mFeatureFlags,
mock(DumpManager.class),
new FakeDisplayTracker(mContext));
}
@@ -211,8 +200,6 @@
@Test
public void validateNavBarChangesUpdateIcons() {
- assumeTrue(testNewLightBarLogic()); // Only run in the new suite
-
// On the launcher in dark mode buttons are light
mLightBarController.setScrimState(ScrimState.UNLOCKED, 0f, COLORS_DARK);
mLightBarController.onNavigationBarAppearanceChanged(
@@ -251,8 +238,6 @@
@Test
public void navBarHasDarkIconsInLockedShade_lightMode() {
- assumeTrue(testNewLightBarLogic()); // Only run in the new suite
-
// On the locked shade QS in light mode buttons are light
mLightBarController.setScrimState(ScrimState.SHADE_LOCKED, 1f, COLORS_LIGHT);
mLightBarController.onNavigationBarAppearanceChanged(
@@ -287,8 +272,6 @@
@Test
public void navBarHasLightIconsInLockedShade_darkMode() {
- assumeTrue(testNewLightBarLogic()); // Only run in the new suite
-
// On the locked shade QS in light mode buttons are light
mLightBarController.setScrimState(ScrimState.SHADE_LOCKED, 1f, COLORS_DARK);
mLightBarController.onNavigationBarAppearanceChanged(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerWithNewLogicTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerWithNewLogicTest.kt
deleted file mode 100644
index d9c2cfa..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerWithNewLogicTest.kt
+++ /dev/null
@@ -1,28 +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.statusbar.phone
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.flags.Flags.NEW_LIGHT_BAR_LOGIC
-
-/**
- * This file only needs to live as long as [NEW_LIGHT_BAR_LOGIC] does. When we delete that flag, we
- * can roll this back into the old test.
- */
-@SmallTest
-class LightBarControllerWithNewLogicTest : LightBarControllerTest() {
- override fun testNewLightBarLogic(): Boolean = true
-}
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..33c77cc 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,10 @@
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 +122,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,11 +136,11 @@
@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.)
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- @Mock private FeatureFlags mFeatureFlags;
private static class AnimatorListener implements Animator.AnimatorListener {
private int mNumStarts;
@@ -181,10 +184,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 +217,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);
@@ -267,8 +278,7 @@
mPrimaryBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
mMainDispatcher,
- mLinearLargeScreenShadeInterpolator,
- mFeatureFlags);
+ mLinearLargeScreenShadeInterpolator);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -576,7 +586,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 +594,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 +650,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
@@ -938,8 +971,7 @@
mPrimaryBouncerToGoneTransitionViewModel,
mKeyguardTransitionInteractor,
mMainDispatcher,
- mLinearLargeScreenShadeInterpolator,
- mFeatureFlags);
+ mLinearLargeScreenShadeInterpolator);
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
@@ -1764,6 +1796,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/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index 8aaa57f..9157cd9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -16,7 +16,6 @@
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
-import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
import static junit.framework.Assert.assertTrue;
@@ -41,13 +40,11 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
-import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
import com.android.systemui.statusbar.pipeline.wifi.ui.WifiUiAdapter;
@@ -156,13 +153,9 @@
assertTrue("Expected StatusBarIconView",
(manager.getViewAt(0) instanceof StatusBarIconView));
- holder = holderForType(TYPE_WIFI);
- manager.onIconAdded(1, "test_wifi", false, holder);
- assertTrue(manager.getViewAt(1) instanceof StatusBarWifiView);
-
holder = holderForType(TYPE_MOBILE);
- manager.onIconAdded(2, "test_mobile", false, holder);
- assertTrue(manager.getViewAt(2) instanceof StatusBarMobileView);
+ manager.onIconAdded(1, "test_mobile", false, holder);
+ assertTrue(manager.getViewAt(1) instanceof StatusBarMobileView);
}
private StatusBarIconHolder holderForType(int type) {
@@ -170,9 +163,6 @@
case TYPE_MOBILE:
return StatusBarIconHolder.fromMobileIconState(mock(MobileIconState.class));
- case TYPE_WIFI:
- return StatusBarIconHolder.fromWifiIconState(mock(WifiIconState.class));
-
case TYPE_ICON:
default:
return StatusBarIconHolder.fromIcon(mock(StatusBarIcon.class));
@@ -214,13 +204,6 @@
}
@Override
- protected StatusBarWifiView addWifiIcon(int index, String slot, WifiIconState state) {
- StatusBarWifiView mock = mock(StatusBarWifiView.class);
- mGroup.addView(mock, index);
- return mock;
- }
-
- @Override
protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
StatusBarMobileView mock = mock(StatusBarMobileView.class);
mGroup.addView(mock, index);
@@ -254,13 +237,6 @@
}
@Override
- protected StatusBarWifiView addWifiIcon(int index, String slot, WifiIconState state) {
- StatusBarWifiView mock = mock(StatusBarWifiView.class);
- mGroup.addView(mock, index);
- return mock;
- }
-
- @Override
protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
StatusBarMobileView mock = mock(StatusBarMobileView.class);
mGroup.addView(mock, index);
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/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index d44af88..9c7f619 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -21,6 +21,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.AdditionalAnswers.answerVoid;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -61,10 +63,14 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.data.repository.FakePowerRepository;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.ShadeControllerImpl;
@@ -110,6 +116,8 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
+ private static final int DISPLAY_ID = 0;
+
@Mock
private AssistManager mAssistManager;
@Mock
@@ -118,13 +126,12 @@
private NotificationClickNotifier mClickNotifier;
@Mock
private StatusBarStateController mStatusBarStateController;
+ @Mock private ScreenOffAnimationController mScreenOffAnimationController;
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
private NotificationRemoteInputManager mRemoteInputManager;
@Mock
- private CentralSurfaces mCentralSurfaces;
- @Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
@@ -150,6 +157,8 @@
private ActivityLaunchAnimator mActivityLaunchAnimator;
@Mock
private InteractionJankMonitor mJankMonitor;
+ private FakePowerRepository mPowerRepository;
+ private PowerInteractor mPowerInteractor;
@Mock
private UserTracker mUserTracker;
private final FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -199,6 +208,14 @@
when(mUserTracker.getUserHandle()).thenReturn(
UserHandle.of(ActivityManager.getCurrentUser()));
+ mPowerRepository = new FakePowerRepository();
+ mPowerInteractor = new PowerInteractor(
+ mPowerRepository,
+ new FakeKeyguardRepository(),
+ new FalsingCollectorFake(),
+ mScreenOffAnimationController,
+ mStatusBarStateController);
+
HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider =
new NotificationLaunchAnimatorControllerProvider(
@@ -209,6 +226,7 @@
mNotificationActivityStarter =
new StatusBarNotificationActivityStarter(
getContext(),
+ DISPLAY_ID,
mHandler,
mUiBgExecutor,
mVisibilityProvider,
@@ -231,13 +249,13 @@
mock(MetricsLogger.class),
mock(StatusBarNotificationActivityStarterLogger.class),
mOnUserInteractionCallback,
- mCentralSurfaces,
mock(NotificationPresenter.class),
mock(ShadeViewController.class),
mock(NotificationShadeWindowController.class),
mActivityLaunchAnimator,
notificationAnimationProvider,
mock(LaunchFullScreenIntentProvider.class),
+ mPowerInteractor,
mock(FeatureFlags.class),
mUserTracker
);
@@ -274,7 +292,7 @@
notification.flags |= Notification.FLAG_AUTO_CANCEL;
when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mCentralSurfaces.isOccluded()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
// When
mNotificationActivityStarter.onNotificationClicked(entry, mNotificationRow);
@@ -340,7 +358,7 @@
// Given
sbn.getNotification().contentIntent = null;
when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mCentralSurfaces.isOccluded()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
// When
mNotificationActivityStarter.onNotificationClicked(entry, mBubbleNotificationRow);
@@ -368,7 +386,7 @@
// Given
sbn.getNotification().contentIntent = mContentIntent;
when(mKeyguardStateController.isShowing()).thenReturn(true);
- when(mCentralSurfaces.isOccluded()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(true);
// When
mNotificationActivityStarter.onNotificationClicked(entry, mBubbleNotificationRow);
@@ -402,11 +420,13 @@
when(entry.getImportance()).thenReturn(NotificationManager.IMPORTANCE_HIGH);
when(entry.getSbn()).thenReturn(sbn);
- // WHEN
+ // WHEN the intent is launched while dozing
+ when(mStatusBarStateController.isDozing()).thenReturn(true);
mNotificationActivityStarter.launchFullScreenIntent(entry);
// THEN display should try wake up for the full screen intent
- verify(mCentralSurfaces).wakeUpForFullScreenIntent();
+ assertThat(mPowerRepository.getLastWakeReason()).isNotNull();
+ assertThat(mPowerRepository.getLastWakeWhy()).isNotNull();
}
@Test
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/stylus/StylusUsiPowerUiTest.kt b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
index 90821bd..d212c02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/stylus/StylusUsiPowerUiTest.kt
@@ -126,6 +126,16 @@
}
@Test
+ fun updateBatteryState_capacitySame_inputDeviceChanges_updatesInputDeviceId() {
+ stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
+ stylusUsiPowerUi.updateBatteryState(1, FixedCapacityBatteryState(0.1f))
+
+ assertThat(stylusUsiPowerUi.inputDeviceId).isEqualTo(1)
+ verify(notificationManager, times(1))
+ .notify(eq(R.string.stylus_battery_low_percentage), any())
+ }
+
+ @Test
fun updateBatteryState_existingNotification_capacityAboveThreshold_cancelsNotification() {
stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.1f))
stylusUsiPowerUi.updateBatteryState(0, FixedCapacityBatteryState(0.8f))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 27957ed..f299ad4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -28,6 +28,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.app.Application;
@@ -36,6 +37,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Build;
import android.os.Parcel;
@@ -74,6 +76,8 @@
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -400,6 +404,18 @@
verify(mToastLogger, never()).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
}
+ @Test
+ public void testShowToast_invalidDisplayId_logsAndSkipsToast() {
+ int invalidDisplayId = getInvalidDisplayId();
+
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mCallback, invalidDisplayId);
+
+ verify(mToastLogger).logOnSkipToastForInvalidDisplay(PACKAGE_NAME_1, TOKEN_1.toString(),
+ invalidDisplayId);
+ verifyZeroInteractions(mWindowManager);
+ }
+
private View verifyWmAddViewAndAttachToParent() {
ArgumentCaptor<View> viewCaptor = ArgumentCaptor.forClass(View.class);
verify(mWindowManager).addView(viewCaptor.capture(), any());
@@ -416,4 +432,10 @@
return null;
};
}
+
+ private int getInvalidDisplayId() {
+ return Arrays.stream(
+ mContext.getSystemService(DisplayManager.class).getDisplays())
+ .map(Display::getDisplayId).max(Integer::compare).get() + 1;
+ }
}
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/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 8f725be..0c77529 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -142,6 +142,7 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
+ false,
mCsdWarningDialogFactory,
mPostureController,
mTestableLooper.getLooper(),
@@ -378,6 +379,7 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
+ false,
mCsdWarningDialogFactory,
devicePostureController,
mTestableLooper.getLooper(),
@@ -397,6 +399,8 @@
int gravity = dialog.getWindowGravity();
assertEquals(Gravity.TOP, gravity & Gravity.VERTICAL_GRAVITY_MASK);
+
+ cleanUp(dialog);
}
@Test
@@ -415,6 +419,7 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
+ false,
mCsdWarningDialogFactory,
devicePostureController,
mTestableLooper.getLooper(),
@@ -433,6 +438,8 @@
int gravity = dialog.getWindowGravity();
assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
+
+ cleanUp(dialog);
}
@Test
@@ -451,6 +458,7 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
+ false,
mCsdWarningDialogFactory,
devicePostureController,
mTestableLooper.getLooper(),
@@ -469,6 +477,8 @@
int gravity = dialog.getWindowGravity();
assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
+
+ cleanUp(dialog);
}
@Test
@@ -489,18 +499,19 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
+ false,
mCsdWarningDialogFactory,
mPostureController,
mTestableLooper.getLooper(),
- mDumpManager
- );
+ mDumpManager);
dialog.init(0, null);
verify(mPostureController, never()).removeCallback(any());
-
dialog.destroy();
verify(mPostureController).removeCallback(any());
+
+ cleanUp(dialog);
}
private void setOrientation(int orientation) {
@@ -513,14 +524,18 @@
@After
public void teardown() {
- if (mDialog != null) {
- mDialog.clearInternalHandlerAfterTest();
- }
+ cleanUp(mDialog);
setOrientation(mOriginalOrientation);
mTestableLooper.processAllMessages();
reset(mPostureController);
}
+ private void cleanUp(VolumeDialogImpl dialog) {
+ if (dialog != null) {
+ dialog.clearInternalHandlerAfterTest();
+ }
+ }
+
/*
@Test
public void testContentDescriptions() {
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 ef12b2a..4839eeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -1996,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/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 9de7a87..ef0adbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -34,7 +34,6 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
@@ -76,7 +75,6 @@
@Mock SplitScreen mSplitScreen;
@Mock OneHanded mOneHanded;
@Mock WakefulnessLifecycle mWakefulnessLifecycle;
- @Mock ProtoTracer mProtoTracer;
@Mock UserTracker mUserTracker;
@Mock ShellExecutor mSysUiMainExecutor;
@Mock NoteTaskInitializer mNoteTaskInitializer;
@@ -99,7 +97,6 @@
mKeyguardUpdateMonitor,
mScreenLifecycle,
mSysUiState,
- mProtoTracer,
mWakefulnessLifecycle,
mUserTracker,
displayTracker,
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..28892ba 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,165 @@
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 = HINTING_PIN_LENGTH
+
+ 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 ?: DEFAULT_PIN).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,
+ )
+ }
+ }
+
+ private fun getExpectedCredential(securityMode: SecurityMode): List<Any> {
+ return when (val credentialType = getCurrentCredentialType(securityMode)) {
+ LockPatternUtils.CREDENTIAL_TYPE_PIN -> credentialOverride ?: DEFAULT_PIN
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD -> "password".toList()
+ LockPatternUtils.CREDENTIAL_TYPE_PATTERN -> PATTERN.toCells()
+ else -> error("Unsupported credential type $credentialType!")
+ }
+ }
+
+ 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
+ const val HINTING_PIN_LENGTH = 6
+ val DEFAULT_PIN = buildList { repeat(HINTING_PIN_LENGTH) { add(it + 1) } }
+
+ private fun AuthenticationMethodModel.toSecurityMode(): SecurityMode {
return when (this) {
is AuthenticationMethodModel.Pin -> SecurityMode.PIN
is AuthenticationMethodModel.Password -> SecurityMode.Password
@@ -58,5 +183,41 @@
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 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/biometrics/data/repository/FakeFingerprintPropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
index 2362a52..0c5e438 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFingerprintPropertyRepository.kt
@@ -20,16 +20,12 @@
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
class FakeFingerprintPropertyRepository : FingerprintPropertyRepository {
- private val _isInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false)
- override val isInitialized = _isInitialized.asStateFlow()
-
private val _sensorId: MutableStateFlow<Int> = MutableStateFlow(-1)
- override val sensorId: StateFlow<Int> = _sensorId.asStateFlow()
+ override val sensorId = _sensorId.asStateFlow()
private val _strength: MutableStateFlow<SensorStrength> =
MutableStateFlow(SensorStrength.CONVENIENCE)
@@ -37,12 +33,11 @@
private val _sensorType: MutableStateFlow<FingerprintSensorType> =
MutableStateFlow(FingerprintSensorType.UNKNOWN)
- override val sensorType: StateFlow<FingerprintSensorType> = _sensorType.asStateFlow()
+ override val sensorType = _sensorType.asStateFlow()
private val _sensorLocations: MutableStateFlow<Map<String, SensorLocationInternal>> =
MutableStateFlow(mapOf("" to SensorLocationInternal.DEFAULT))
- override val sensorLocations: StateFlow<Map<String, SensorLocationInternal>> =
- _sensorLocations.asStateFlow()
+ override val sensorLocations = _sensorLocations.asStateFlow()
fun setProperties(
sensorId: Int,
@@ -54,6 +49,5 @@
_strength.value = strength
_sensorType.value = sensorType
_sensorLocations.value = sensorLocations
- _isInitialized.value = true
}
}
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..6309740 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
@@ -48,7 +48,7 @@
override val isKeyguardShowing: Flow<Boolean> = _isKeyguardShowing
private val _isKeyguardUnlocked = MutableStateFlow(false)
- override val isKeyguardUnlocked: Flow<Boolean> = _isKeyguardUnlocked
+ override val isKeyguardUnlocked: StateFlow<Boolean> = _isKeyguardUnlocked.asStateFlow()
private val _isKeyguardOccluded = MutableStateFlow(false)
override val isKeyguardOccluded: Flow<Boolean> = _isKeyguardOccluded
@@ -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..47e1daf4 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,41 @@
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.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.LockscreenSceneInteractor
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
import com.android.systemui.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,24 +60,37 @@
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)
+ set(Flags.FACE_AUTH_REFACTOR, false)
+ }
+ 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 },
)
}
+ val keyguardRepository: FakeKeyguardRepository by lazy {
+ FakeKeyguardRepository().apply {
+ setWakefulnessModel(
+ WakefulnessModel(
+ WakefulnessState.AWAKE,
+ WakeSleepReason.OTHER,
+ WakeSleepReason.OTHER,
+ )
+ )
+ }
+ }
private val context = test.context
fun fakeSceneContainerRepository(
@@ -105,7 +130,7 @@
)
}
- fun authenticationRepository(): AuthenticationRepository {
+ fun authenticationRepository(): FakeAuthenticationRepository {
return authenticationRepository
}
@@ -115,6 +140,23 @@
return AuthenticationInteractor(
applicationScope = applicationScope(),
repository = repository,
+ backgroundDispatcher = testDispatcher,
+ userRepository = userRepository,
+ clock = mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } }
+ )
+ }
+
+ fun keyguardRepository(): FakeKeyguardRepository {
+ return keyguardRepository
+ }
+
+ fun keyguardInteractor(repository: KeyguardRepository): KeyguardInteractor {
+ return KeyguardInteractor(
+ repository = repository,
+ commandQueue = FakeCommandQueue(),
+ featureFlags = featureFlags,
+ bouncerRepository = FakeKeyguardBouncerRepository(),
+ configurationRepository = FakeConfigurationRepository()
)
}
@@ -128,6 +170,7 @@
repository = BouncerRepository(),
authenticationInteractor = authenticationInteractor,
sceneInteractor = sceneInteractor,
+ featureFlags = featureFlags,
containerName = CONTAINER_1,
)
}
@@ -144,13 +187,13 @@
return bouncerInteractor
}
},
+ featureFlags = featureFlags,
containerName = CONTAINER_1,
)
}
fun lockScreenSceneInteractor(
authenticationInteractor: AuthenticationInteractor,
- sceneInteractor: SceneInteractor,
bouncerInteractor: BouncerInteractor,
): LockscreenSceneInteractor {
return LockscreenSceneInteractor(
@@ -162,7 +205,6 @@
return bouncerInteractor
}
},
- sceneInteractor = sceneInteractor,
containerName = CONTAINER_1,
)
}
@@ -172,7 +214,7 @@
}
companion object {
- const val CONTAINER_1 = "container1"
+ const val CONTAINER_1 = SceneContainerNames.SYSTEM_UI_DEFAULT
const val CONTAINER_2 = "container2"
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index c664c99..56837e8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -21,7 +21,6 @@
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
-import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import java.util.List;
@@ -62,10 +61,6 @@
}
@Override
- public void setWifiIcon(String slot, WifiIconState state) {
- }
-
- @Override
public void setNewWifiIcon() {
}
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/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..7557071 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/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index cd2f844..254e6ce 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -1094,8 +1094,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/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 578f520..c30b522 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4984,7 +4984,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/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/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index e51fc0a..a682c85 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1713,6 +1713,11 @@
}
}
+ private boolean isScreenOnOrAnimatingLocked(ProcessStateRecord state) {
+ return mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE
+ || state.isRunningRemoteAnimation();
+ }
+
@GuardedBy({"mService", "mProcLock"})
private boolean computeOomAdjLSP(ProcessRecord app, int cachedAdj,
ProcessRecord topApp, boolean doingAll, long now, boolean cycleReEval,
@@ -1794,8 +1799,7 @@
state.setSystemNoUi(false);
}
if (!state.isSystemNoUi()) {
- if (mService.mWakefulness.get() == PowerManagerInternal.WAKEFULNESS_AWAKE
- || state.isRunningRemoteAnimation()) {
+ if (isScreenOnOrAnimatingLocked(state)) {
// screen on or animating, promote UI
state.setCurProcState(ActivityManager.PROCESS_STATE_PERSISTENT_UI);
state.setCurrentSchedulingGroup(SCHED_GROUP_TOP_APP);
@@ -3281,8 +3285,10 @@
} else {
setThreadPriority(app.getPid(), THREAD_PRIORITY_TOP_APP_BOOST);
}
- initialSchedGroup = SCHED_GROUP_TOP_APP;
- initialProcState = PROCESS_STATE_TOP;
+ if (isScreenOnOrAnimatingLocked(state)) {
+ initialSchedGroup = SCHED_GROUP_TOP_APP;
+ initialProcState = PROCESS_STATE_TOP;
+ }
initialCapability = PROCESS_CAPABILITY_ALL;
initialCached = false;
} catch (Exception e) {
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/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index ca15dd7..c6d6122 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -40,6 +40,7 @@
import android.app.GameState;
import android.app.IGameManagerService;
import android.app.IGameModeListener;
+import android.app.IGameStateListener;
import android.app.StatsManager;
import android.app.UidObserver;
import android.content.BroadcastReceiver;
@@ -148,6 +149,7 @@
private final Object mLock = new Object();
private final Object mDeviceConfigLock = new Object();
private final Object mGameModeListenerLock = new Object();
+ private final Object mGameStateListenerLock = new Object();
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
final Handler mHandler;
private final PackageManager mPackageManager;
@@ -164,6 +166,8 @@
// listener to caller uid map
@GuardedBy("mGameModeListenerLock")
private final ArrayMap<IGameModeListener, Integer> mGameModeListeners = new ArrayMap<>();
+ @GuardedBy("mGameStateListenerLock")
+ private final ArrayMap<IGameStateListener, Integer> mGameStateListeners = new ArrayMap<>();
@Nullable
private final GameServiceController mGameServiceController;
private final Object mUidObserverLock = new Object();
@@ -352,6 +356,16 @@
loadingBoostDuration);
}
}
+ synchronized (mGameStateListenerLock) {
+ for (IGameStateListener listener : mGameStateListeners.keySet()) {
+ try {
+ listener.onGameStateChanged(packageName, gameState, userId);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Cannot notify game state change for listener added by "
+ + mGameStateListeners.get(listener));
+ }
+ }
+ }
break;
}
case CANCEL_GAME_LOADING_MODE: {
@@ -1474,6 +1488,43 @@
}
/**
+ * Adds a game state listener.
+ */
+ @Override
+ public void addGameStateListener(@NonNull IGameStateListener listener) {
+ try {
+ final IBinder listenerBinder = listener.asBinder();
+ listenerBinder.linkToDeath(new DeathRecipient() {
+ @Override public void binderDied() {
+ removeGameStateListenerUnchecked(listener);
+ listenerBinder.unlinkToDeath(this, 0 /*flags*/);
+ }
+ }, 0 /*flags*/);
+ synchronized (mGameStateListenerLock) {
+ mGameStateListeners.put(listener, Binder.getCallingUid());
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG,
+ "Failed to link death recipient for IGameStateListener from caller "
+ + Binder.getCallingUid() + ", abandoned its listener registration", ex);
+ }
+ }
+
+ /**
+ * Removes a game state listener.
+ */
+ @Override
+ public void removeGameStateListener(@NonNull IGameStateListener listener) {
+ removeGameStateListenerUnchecked(listener);
+ }
+
+ private void removeGameStateListenerUnchecked(IGameStateListener listener) {
+ synchronized (mGameStateListenerLock) {
+ mGameStateListeners.remove(listener);
+ }
+ }
+
+ /**
* Notified when boot is completed.
*/
@VisibleForTesting
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java b/services/core/java/com/android/server/biometrics/BiometricCameraManager.java
similarity index 71%
rename from services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java
rename to services/core/java/com/android/server/biometrics/BiometricCameraManager.java
index 6727fbc..058ea6b 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacy.java
+++ b/services/core/java/com/android/server/biometrics/BiometricCameraManager.java
@@ -17,9 +17,16 @@
package com.android.server.biometrics;
/**
- * Interface for biometric operations to get camera privacy state.
+ * Interface for biometrics to get camera status.
*/
-public interface BiometricSensorPrivacy {
- /* Returns true if privacy is enabled and camera access is disabled. */
+public interface BiometricCameraManager {
+ /**
+ * Returns true if any camera is in use.
+ */
+ boolean isAnyCameraUnavailable();
+
+ /**
+ * Returns true if privacy is enabled and camera access is disabled.
+ */
boolean isCameraPrivacyEnabled();
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
new file mode 100644
index 0000000..000ee54
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java
@@ -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.server.biometrics;
+
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+
+import android.annotation.NonNull;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.camera2.CameraManager;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class BiometricCameraManagerImpl implements BiometricCameraManager {
+
+ private final CameraManager mCameraManager;
+ private final SensorPrivacyManager mSensorPrivacyManager;
+ private final ConcurrentHashMap<String, Boolean> mIsCameraAvailable = new ConcurrentHashMap<>();
+
+ private final CameraManager.AvailabilityCallback mCameraAvailabilityCallback =
+ new CameraManager.AvailabilityCallback() {
+ @Override
+ public void onCameraAvailable(@NonNull String cameraId) {
+ mIsCameraAvailable.put(cameraId, true);
+ }
+
+ @Override
+ public void onCameraUnavailable(@NonNull String cameraId) {
+ mIsCameraAvailable.put(cameraId, false);
+ }
+ };
+
+ public BiometricCameraManagerImpl(@NonNull CameraManager cameraManager,
+ @NonNull SensorPrivacyManager sensorPrivacyManager) {
+ mCameraManager = cameraManager;
+ mSensorPrivacyManager = sensorPrivacyManager;
+ mCameraManager.registerAvailabilityCallback(mCameraAvailabilityCallback, null);
+ }
+
+ @Override
+ public boolean isAnyCameraUnavailable() {
+ for (String cameraId : mIsCameraAvailable.keySet()) {
+ if (!mIsCameraAvailable.get(cameraId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isCameraPrivacyEnabled() {
+ return mSensorPrivacyManager != null && mSensorPrivacyManager
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, CAMERA);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java b/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java
deleted file mode 100644
index b6701da..0000000
--- a/services/core/java/com/android/server/biometrics/BiometricSensorPrivacyImpl.java
+++ /dev/null
@@ -1,37 +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.biometrics;
-
-import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
-
-import android.annotation.Nullable;
-import android.hardware.SensorPrivacyManager;
-
-public class BiometricSensorPrivacyImpl implements
- BiometricSensorPrivacy {
- private final SensorPrivacyManager mSensorPrivacyManager;
-
- public BiometricSensorPrivacyImpl(@Nullable SensorPrivacyManager sensorPrivacyManager) {
- mSensorPrivacyManager = sensorPrivacyManager;
- }
-
- @Override
- public boolean isCameraPrivacyEnabled() {
- return mSensorPrivacyManager != null && mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, CAMERA);
- }
-}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 1fa97a3..e8ffe4f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -48,6 +48,7 @@
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
+import android.hardware.camera2.CameraManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.net.Uri;
@@ -125,7 +126,7 @@
AuthSession mAuthSession;
private final Handler mHandler = new Handler(Looper.getMainLooper());
- private final BiometricSensorPrivacy mBiometricSensorPrivacy;
+ private final BiometricCameraManager mBiometricCameraManager;
/**
* Tracks authenticatorId invalidation. For more details, see
@@ -936,7 +937,7 @@
return PreAuthInfo.create(mTrustManager, mDevicePolicyManager, mSettingObserver, mSensors,
userId, promptInfo, opPackageName, false /* checkDevicePolicyManager */,
- getContext(), mBiometricSensorPrivacy);
+ getContext(), mBiometricCameraManager);
}
/**
@@ -1030,9 +1031,9 @@
return context.getSystemService(UserManager.class);
}
- public BiometricSensorPrivacy getBiometricSensorPrivacy(Context context) {
- return new BiometricSensorPrivacyImpl(context.getSystemService(
- SensorPrivacyManager.class));
+ public BiometricCameraManager getBiometricCameraManager(Context context) {
+ return new BiometricCameraManagerImpl(context.getSystemService(CameraManager.class),
+ context.getSystemService(SensorPrivacyManager.class));
}
}
@@ -1062,7 +1063,7 @@
mRequestCounter = mInjector.getRequestGenerator();
mBiometricContext = injector.getBiometricContext(context);
mUserManager = injector.getUserManager(context);
- mBiometricSensorPrivacy = injector.getBiometricSensorPrivacy(context);
+ mBiometricCameraManager = injector.getBiometricCameraManager(context);
try {
injector.getActivityManagerService().registerUserSwitchObserver(
@@ -1299,7 +1300,7 @@
final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager,
mDevicePolicyManager, mSettingObserver, mSensors, userId, promptInfo,
opPackageName, promptInfo.isDisallowBiometricsIfPolicyExists(),
- getContext(), mBiometricSensorPrivacy);
+ getContext(), mBiometricCameraManager);
final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index e6f25cb..b1740a7 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -72,16 +72,16 @@
final Context context;
private final boolean mBiometricRequested;
private final int mBiometricStrengthRequested;
- private final BiometricSensorPrivacy mBiometricSensorPrivacy;
+ private final BiometricCameraManager mBiometricCameraManager;
private PreAuthInfo(boolean biometricRequested, int biometricStrengthRequested,
boolean credentialRequested, List<BiometricSensor> eligibleSensors,
List<Pair<BiometricSensor, Integer>> ineligibleSensors, boolean credentialAvailable,
boolean confirmationRequested, boolean ignoreEnrollmentState, int userId,
- Context context, BiometricSensorPrivacy biometricSensorPrivacy) {
+ Context context, BiometricCameraManager biometricCameraManager) {
mBiometricRequested = biometricRequested;
mBiometricStrengthRequested = biometricStrengthRequested;
- mBiometricSensorPrivacy = biometricSensorPrivacy;
+ mBiometricCameraManager = biometricCameraManager;
this.credentialRequested = credentialRequested;
this.eligibleSensors = eligibleSensors;
@@ -99,7 +99,7 @@
List<BiometricSensor> sensors,
int userId, PromptInfo promptInfo, String opPackageName,
boolean checkDevicePolicyManager, Context context,
- BiometricSensorPrivacy biometricSensorPrivacy)
+ BiometricCameraManager biometricCameraManager)
throws RemoteException {
final boolean confirmationRequested = promptInfo.isConfirmationRequested();
@@ -127,7 +127,7 @@
checkDevicePolicyManager, requestedStrength,
promptInfo.getAllowedSensorIds(),
promptInfo.isIgnoreEnrollmentState(),
- biometricSensorPrivacy);
+ biometricCameraManager);
Slog.d(TAG, "Package: " + opPackageName
+ " Sensor ID: " + sensor.id
@@ -151,7 +151,7 @@
return new PreAuthInfo(biometricRequested, requestedStrength, credentialRequested,
eligibleSensors, ineligibleSensors, credentialAvailable, confirmationRequested,
- promptInfo.isIgnoreEnrollmentState(), userId, context, biometricSensorPrivacy);
+ promptInfo.isIgnoreEnrollmentState(), userId, context, biometricCameraManager);
}
/**
@@ -168,12 +168,16 @@
BiometricSensor sensor, int userId, String opPackageName,
boolean checkDevicePolicyManager, int requestedStrength,
@NonNull List<Integer> requestedSensorIds,
- boolean ignoreEnrollmentState, BiometricSensorPrivacy biometricSensorPrivacy) {
+ boolean ignoreEnrollmentState, BiometricCameraManager biometricCameraManager) {
if (!requestedSensorIds.isEmpty() && !requestedSensorIds.contains(sensor.id)) {
return BIOMETRIC_NO_HARDWARE;
}
+ if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) {
+ return BIOMETRIC_HARDWARE_NOT_DETECTED;
+ }
+
final boolean wasStrongEnough =
Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength);
final boolean isStrongEnough =
@@ -195,8 +199,8 @@
return BIOMETRIC_NOT_ENROLLED;
}
- if (biometricSensorPrivacy != null && sensor.modality == TYPE_FACE) {
- if (biometricSensorPrivacy.isCameraPrivacyEnabled()) {
+ if (biometricCameraManager != null && sensor.modality == TYPE_FACE) {
+ if (biometricCameraManager.isCameraPrivacyEnabled()) {
//Camera privacy is enabled as the access is disabled
return BIOMETRIC_SENSOR_PRIVACY_ENABLED;
}
@@ -307,8 +311,8 @@
@BiometricAuthenticator.Modality int modality = TYPE_NONE;
boolean cameraPrivacyEnabled = false;
- if (mBiometricSensorPrivacy != null) {
- cameraPrivacyEnabled = mBiometricSensorPrivacy.isCameraPrivacyEnabled();
+ if (mBiometricCameraManager != null) {
+ cameraPrivacyEnabled = mBiometricCameraManager.isCameraPrivacyEnabled();
}
if (mBiometricRequested && credentialRequested) {
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 06417d7..f51b62d 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -66,7 +66,6 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
-import java.util.ArrayList;
import java.util.List;
public class Utils {
@@ -98,33 +97,6 @@
}
/**
- * Get the enabled HAL instances. If virtual is enabled and available it will be returned as
- * the only instance, otherwise all other instances will be returned.
- *
- * @param context system context
- * @param declaredInstances known instances
- * @return filtered list of enabled instances
- */
- @NonNull
- public static List<String> filterAvailableHalInstances(@NonNull Context context,
- @NonNull List<String> declaredInstances) {
- if (declaredInstances.size() <= 1) {
- return declaredInstances;
- }
-
- final int virtualAt = declaredInstances.indexOf("virtual");
- if (isVirtualEnabled(context) && virtualAt != -1) {
- return List.of(declaredInstances.get(virtualAt));
- }
-
- declaredInstances = new ArrayList<>(declaredInstances);
- if (virtualAt != -1) {
- declaredInstances.remove(virtualAt);
- }
- return declaredInstances;
- }
-
- /**
* Combines {@link PromptInfo#setDeviceCredentialAllowed(boolean)} with
* {@link PromptInfo#setAuthenticators(int)}, as the former is not flexible enough.
*/
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 28cb7d9..7cc6940 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -871,19 +871,22 @@
super.registerAuthenticators_enforcePermission();
mRegistry.registerAll(() -> {
- final List<ServiceProvider> providers = new ArrayList<>();
- providers.addAll(getHidlProviders(hidlSensors));
List<String> aidlSensors = new ArrayList<>();
final String[] instances = mAidlInstanceNameSupplier.get();
if (instances != null) {
aidlSensors.addAll(Lists.newArrayList(instances));
}
- providers.addAll(getAidlProviders(
- Utils.filterAvailableHalInstances(getContext(), aidlSensors)));
+
+ final Pair<List<FingerprintSensorPropertiesInternal>, List<String>>
+ filteredInstances = filterAvailableHalInstances(hidlSensors, aidlSensors);
+
+ final List<ServiceProvider> providers = new ArrayList<>();
+ providers.addAll(getHidlProviders(filteredInstances.first));
+ providers.addAll(getAidlProviders(filteredInstances.second));
+
return providers;
});
}
-
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void addAuthenticatorsRegisteredCallback(
@@ -1038,6 +1041,33 @@
});
}
+ private Pair<List<FingerprintSensorPropertiesInternal>, List<String>>
+ filterAvailableHalInstances(
+ @NonNull List<FingerprintSensorPropertiesInternal> hidlInstances,
+ @NonNull List<String> aidlInstances) {
+ if ((hidlInstances.size() + aidlInstances.size()) <= 1) {
+ return new Pair(hidlInstances, aidlInstances);
+ }
+
+ final int virtualAt = aidlInstances.indexOf("virtual");
+ if (Utils.isVirtualEnabled(getContext())) {
+ if (virtualAt != -1) {
+ //only virtual instance should be returned
+ return new Pair(new ArrayList<>(), List.of(aidlInstances.get(virtualAt)));
+ } else {
+ Slog.e(TAG, "Could not find virtual interface while it is enabled");
+ return new Pair(hidlInstances, aidlInstances);
+ }
+ } else {
+ //remove virtual instance
+ aidlInstances = new ArrayList<>(aidlInstances);
+ if (virtualAt != -1) {
+ aidlInstances.remove(virtualAt);
+ }
+ return new Pair(hidlInstances, aidlInstances);
+ }
+ }
+
@NonNull
private List<ServiceProvider> getHidlProviders(
@NonNull List<FingerprintSensorPropertiesInternal> hidlSensors) {
diff --git a/services/core/java/com/android/server/display/BrightnessThrottler.java b/services/core/java/com/android/server/display/BrightnessThrottler.java
index c421ec0..59844e1 100644
--- a/services/core/java/com/android/server/display/BrightnessThrottler.java
+++ b/services/core/java/com/android/server/display/BrightnessThrottler.java
@@ -38,17 +38,24 @@
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
import com.android.server.display.feature.DeviceConfigParameterProvider;
+import com.android.server.display.utils.DeviceConfigParsingUtils;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.function.BiFunction;
+import java.util.function.Function;
/**
* This class monitors various conditions, such as skin temperature throttling status, and limits
* the allowed brightness range accordingly.
+ *
+ * @deprecated will be replaced by
+ * {@link com.android.server.display.brightness.clamper.BrightnessThermalClamper}
*/
+@Deprecated
class BrightnessThrottler {
private static final String TAG = "BrightnessThrottler";
private static final boolean DEBUG = false;
@@ -93,8 +100,21 @@
// time the underlying display device changes.
// This map is indexed by uniqueDisplayId, to provide maps for throttlingId -> throttlingData.
// HashMap< uniqueDisplayId, HashMap< throttlingDataId, ThermalBrightnessThrottlingData >>
- private final HashMap<String, HashMap<String, ThermalBrightnessThrottlingData>>
- mThermalBrightnessThrottlingDataOverride = new HashMap<>(1);
+ private final Map<String, Map<String, ThermalBrightnessThrottlingData>>
+ mThermalBrightnessThrottlingDataOverride = new HashMap<>();
+
+ private final BiFunction<String, String, ThrottlingLevel> mDataPointMapper = (key, value) -> {
+ try {
+ int status = DeviceConfigParsingUtils.parseThermalStatus(key);
+ float brightnessPoint = DeviceConfigParsingUtils.parseBrightness(value);
+ return new ThrottlingLevel(status, brightnessPoint);
+ } catch (IllegalArgumentException iae) {
+ return null;
+ }
+ };
+
+ private final Function<List<ThrottlingLevel>, ThermalBrightnessThrottlingData>
+ mDataSetMapper = ThermalBrightnessThrottlingData::create;
BrightnessThrottler(Handler handler, Runnable throttlingChangeCallback, String uniqueDisplayId,
String throttlingDataId,
@@ -257,79 +277,15 @@
// 456,2,moderate,0.9,critical,0.7,id_2
// displayId, number, <state, val> * number
// displayId, <number, <state, val> * number>, throttlingId
- private boolean parseAndAddData(@NonNull String strArray,
- @NonNull HashMap<String, HashMap<String, ThermalBrightnessThrottlingData>>
- displayIdToThrottlingIdToBtd) {
- boolean validConfig = true;
- String[] items = strArray.split(",");
- int i = 0;
-
- try {
- String uniqueDisplayId = items[i++];
-
- // number of throttling points
- int noOfThrottlingPoints = Integer.parseInt(items[i++]);
- List<ThrottlingLevel> throttlingLevels = new ArrayList<>(noOfThrottlingPoints);
-
- // throttling level and point
- for (int j = 0; j < noOfThrottlingPoints; j++) {
- String severity = items[i++];
- int status = parseThermalStatus(severity);
- float brightnessPoint = parseBrightness(items[i++]);
- throttlingLevels.add(new ThrottlingLevel(status, brightnessPoint));
- }
-
- String throttlingDataId = (i < items.length) ? items[i++] : DEFAULT_ID;
- ThermalBrightnessThrottlingData throttlingLevelsData =
- DisplayDeviceConfig.ThermalBrightnessThrottlingData.create(throttlingLevels);
-
- // Add throttlingLevelsData to inner map where necessary.
- HashMap<String, ThermalBrightnessThrottlingData> throttlingMapForDisplay =
- displayIdToThrottlingIdToBtd.get(uniqueDisplayId);
- if (throttlingMapForDisplay == null) {
- throttlingMapForDisplay = new HashMap<>();
- throttlingMapForDisplay.put(throttlingDataId, throttlingLevelsData);
- displayIdToThrottlingIdToBtd.put(uniqueDisplayId, throttlingMapForDisplay);
- } else if (throttlingMapForDisplay.containsKey(throttlingDataId)) {
- Slog.e(TAG, "Throttling data for display " + uniqueDisplayId
- + "contains duplicate throttling ids: '" + throttlingDataId + "'");
- return false;
- } else {
- throttlingMapForDisplay.put(throttlingDataId, throttlingLevelsData);
- }
- } catch (NumberFormatException | IndexOutOfBoundsException
- | UnknownThermalStatusException e) {
- Slog.e(TAG, "Throttling data is invalid array: '" + strArray + "'", e);
- validConfig = false;
- }
-
- if (i != items.length) {
- validConfig = false;
- }
- return validConfig;
- }
-
private void loadThermalBrightnessThrottlingDataFromDeviceConfig() {
- HashMap<String, HashMap<String, ThermalBrightnessThrottlingData>> tempThrottlingData =
- new HashMap<>(1);
mThermalBrightnessThrottlingDataString =
mConfigParameterProvider.getBrightnessThrottlingData();
- boolean validConfig = true;
mThermalBrightnessThrottlingDataOverride.clear();
if (mThermalBrightnessThrottlingDataString != null) {
- String[] throttlingDataSplits = mThermalBrightnessThrottlingDataString.split(";");
- for (String s : throttlingDataSplits) {
- if (!parseAndAddData(s, tempThrottlingData)) {
- validConfig = false;
- break;
- }
- }
-
- if (validConfig) {
- mThermalBrightnessThrottlingDataOverride.putAll(tempThrottlingData);
- tempThrottlingData.clear();
- }
-
+ Map<String, Map<String, ThermalBrightnessThrottlingData>> tempThrottlingData =
+ DeviceConfigParsingUtils.parseDeviceConfigMap(
+ mThermalBrightnessThrottlingDataString, mDataPointMapper, mDataSetMapper);
+ mThermalBrightnessThrottlingDataOverride.putAll(tempThrottlingData);
} else {
Slog.w(TAG, "DeviceConfig ThermalBrightnessThrottlingData is null");
}
@@ -395,42 +351,6 @@
}
}
- private float parseBrightness(String intVal) throws NumberFormatException {
- float value = Float.parseFloat(intVal);
- if (value < PowerManager.BRIGHTNESS_MIN || value > PowerManager.BRIGHTNESS_MAX) {
- throw new NumberFormatException("Brightness constraint value out of bounds.");
- }
- return value;
- }
-
- @PowerManager.ThermalStatus private int parseThermalStatus(@NonNull String value)
- throws UnknownThermalStatusException {
- switch (value) {
- case "none":
- return PowerManager.THERMAL_STATUS_NONE;
- case "light":
- return PowerManager.THERMAL_STATUS_LIGHT;
- case "moderate":
- return PowerManager.THERMAL_STATUS_MODERATE;
- case "severe":
- return PowerManager.THERMAL_STATUS_SEVERE;
- case "critical":
- return PowerManager.THERMAL_STATUS_CRITICAL;
- case "emergency":
- return PowerManager.THERMAL_STATUS_EMERGENCY;
- case "shutdown":
- return PowerManager.THERMAL_STATUS_SHUTDOWN;
- default:
- throw new UnknownThermalStatusException("Invalid Thermal Status: " + value);
- }
- }
-
- private static class UnknownThermalStatusException extends Exception {
- UnknownThermalStatusException(String message) {
- super(message);
- }
- }
-
private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
private final Injector mInjector;
private final Handler mHandler;
diff --git a/services/core/java/com/android/server/display/DisplayBrightnessState.java b/services/core/java/com/android/server/display/DisplayBrightnessState.java
index e27182f..dd5afa2 100644
--- a/services/core/java/com/android/server/display/DisplayBrightnessState.java
+++ b/services/core/java/com/android/server/display/DisplayBrightnessState.java
@@ -16,6 +16,8 @@
package com.android.server.display;
+import android.text.TextUtils;
+
import com.android.server.display.brightness.BrightnessReason;
import java.util.Objects;
@@ -29,12 +31,14 @@
private final float mSdrBrightness;
private final BrightnessReason mBrightnessReason;
private final String mDisplayBrightnessStrategyName;
+ private final boolean mShouldUseAutoBrightness;
private DisplayBrightnessState(Builder builder) {
- this.mBrightness = builder.getBrightness();
- this.mSdrBrightness = builder.getSdrBrightness();
- this.mBrightnessReason = builder.getBrightnessReason();
- this.mDisplayBrightnessStrategyName = builder.getDisplayBrightnessStrategyName();
+ mBrightness = builder.getBrightness();
+ mSdrBrightness = builder.getSdrBrightness();
+ mBrightnessReason = builder.getBrightnessReason();
+ mDisplayBrightnessStrategyName = builder.getDisplayBrightnessStrategyName();
+ mShouldUseAutoBrightness = builder.getShouldUseAutoBrightness();
}
/**
@@ -66,6 +70,13 @@
return mDisplayBrightnessStrategyName;
}
+ /**
+ * @return {@code true} if the device is set up to run auto-brightness.
+ */
+ public boolean getShouldUseAutoBrightness() {
+ return mShouldUseAutoBrightness;
+ }
+
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder("DisplayBrightnessState:");
@@ -75,6 +86,8 @@
stringBuilder.append(getSdrBrightness());
stringBuilder.append("\n brightnessReason:");
stringBuilder.append(getBrightnessReason());
+ stringBuilder.append("\n shouldUseAutoBrightness:");
+ stringBuilder.append(getShouldUseAutoBrightness());
return stringBuilder.toString();
}
@@ -91,28 +104,20 @@
return false;
}
- DisplayBrightnessState
- displayBrightnessState = (DisplayBrightnessState) other;
+ DisplayBrightnessState otherState = (DisplayBrightnessState) other;
- if (mBrightness != displayBrightnessState.getBrightness()) {
- return false;
- }
- if (mSdrBrightness != displayBrightnessState.getSdrBrightness()) {
- return false;
- }
- if (!mBrightnessReason.equals(displayBrightnessState.getBrightnessReason())) {
- return false;
- }
- if (!mDisplayBrightnessStrategyName.equals(
- displayBrightnessState.getDisplayBrightnessStrategyName())) {
- return false;
- }
- return true;
+ return mBrightness == otherState.getBrightness()
+ && mSdrBrightness == otherState.getSdrBrightness()
+ && mBrightnessReason.equals(otherState.getBrightnessReason())
+ && TextUtils.equals(mDisplayBrightnessStrategyName,
+ otherState.getDisplayBrightnessStrategyName())
+ && mShouldUseAutoBrightness == otherState.getShouldUseAutoBrightness();
}
@Override
public int hashCode() {
- return Objects.hash(mBrightness, mSdrBrightness, mBrightnessReason);
+ return Objects.hash(
+ mBrightness, mSdrBrightness, mBrightnessReason, mShouldUseAutoBrightness);
}
/**
@@ -123,6 +128,23 @@
private float mSdrBrightness;
private BrightnessReason mBrightnessReason = new BrightnessReason();
private String mDisplayBrightnessStrategyName;
+ private boolean mShouldUseAutoBrightness;
+
+ /**
+ * Create a builder starting with the values from the specified {@link
+ * DisplayBrightnessState}.
+ *
+ * @param state The state from which to initialize.
+ */
+ public static Builder from(DisplayBrightnessState state) {
+ Builder builder = new Builder();
+ builder.setBrightness(state.getBrightness());
+ builder.setSdrBrightness(state.getSdrBrightness());
+ builder.setBrightnessReason(state.getBrightnessReason());
+ builder.setDisplayBrightnessStrategyName(state.getDisplayBrightnessStrategyName());
+ builder.setShouldUseAutoBrightness(state.getShouldUseAutoBrightness());
+ return builder;
+ }
/**
* Gets the brightness
@@ -200,6 +222,21 @@
}
/**
+ * See {@link DisplayBrightnessState#getShouldUseAutoBrightness}.
+ */
+ public Builder setShouldUseAutoBrightness(boolean shouldUseAutoBrightness) {
+ this.mShouldUseAutoBrightness = shouldUseAutoBrightness;
+ return this;
+ }
+
+ /**
+ * See {@link DisplayBrightnessState#getShouldUseAutoBrightness}.
+ */
+ public boolean getShouldUseAutoBrightness() {
+ return mShouldUseAutoBrightness;
+ }
+
+ /**
* This is used to construct an immutable DisplayBrightnessState object from its builder
*/
public DisplayBrightnessState build() {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index d9cb299..c25b253 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -458,7 +458,7 @@
public static final String QUIRK_CAN_SET_BRIGHTNESS_VIA_HWC = "canSetBrightnessViaHwc";
- static final String DEFAULT_ID = "default";
+ public static final String DEFAULT_ID = "default";
private static final float BRIGHTNESS_DEFAULT = 0.5f;
private static final String ETC_DIR = "etc";
@@ -3127,11 +3127,15 @@
public static class ThermalBrightnessThrottlingData {
public List<ThrottlingLevel> throttlingLevels;
- static class ThrottlingLevel {
+ /**
+ * thermal status to brightness cap holder
+ */
+ public static class ThrottlingLevel {
public @PowerManager.ThermalStatus int thermalStatus;
public float brightness;
- ThrottlingLevel(@PowerManager.ThermalStatus int thermalStatus, float brightness) {
+ public ThrottlingLevel(
+ @PowerManager.ThermalStatus int thermalStatus, float brightness) {
this.thermalStatus = thermalStatus;
this.brightness = brightness;
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 7043af8..7417aeb 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -48,6 +48,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.FloatProperty;
+import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.MathUtils;
import android.util.MutableFloat;
@@ -64,7 +65,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.RingBuffer;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
@@ -73,6 +73,7 @@
import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.brightness.BrightnessUtils;
import com.android.server.display.brightness.DisplayBrightnessController;
+import com.android.server.display.brightness.clamper.BrightnessClamperController;
import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
@@ -380,6 +381,8 @@
private final BrightnessThrottler mBrightnessThrottler;
+ private final BrightnessClamperController mBrightnessClamperController;
+
private final Runnable mOnBrightnessChangeRunnable;
private final BrightnessEvent mLastBrightnessEvent;
@@ -492,7 +495,6 @@
mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(),
() -> updatePowerState(), mDisplayId, mSensorManager);
mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController);
- mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(context, mDisplayId);
mTag = "DisplayPowerController2[" + mDisplayId + "]";
mThermalBrightnessThrottlingDataId =
logicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId;
@@ -554,8 +556,17 @@
mDisplayId, mLogicalDisplay.getDisplayInfoLocked().brightnessDefault,
brightnessSetting, () -> postBrightnessChangeRunnable(),
new HandlerExecutor(mHandler));
+
+ mBrightnessClamperController = new BrightnessClamperController(mHandler,
+ modeChangeCallback::run, new BrightnessClamperController.DisplayDeviceData(
+ mUniqueDisplayId,
+ mThermalBrightnessThrottlingDataId,
+ mDisplayDeviceConfig
+ ));
// Seed the cached brightness
saveBrightnessInfo(getScreenBrightnessSetting());
+ mAutomaticBrightnessStrategy =
+ mDisplayBrightnessController.getAutomaticBrightnessStrategy();
DisplayWhiteBalanceSettings displayWhiteBalanceSettings = null;
DisplayWhiteBalanceController displayWhiteBalanceController = null;
@@ -599,7 +610,7 @@
setUpAutoBrightness(resources, handler);
- mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic();
+ mColorFadeEnabled = mInjector.isColorFadeEnabled();
mColorFadeFadesConfig = resources.getBoolean(
R.bool.config_animateScreenLights);
@@ -782,6 +793,10 @@
final String thermalBrightnessThrottlingDataId =
mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId;
+ mBrightnessClamperController.onDisplayChanged(
+ new BrightnessClamperController.DisplayDeviceData(mUniqueDisplayId,
+ mThermalBrightnessThrottlingDataId, config));
+
mHandler.postAtTime(() -> {
boolean changed = false;
if (mDisplayDevice != device) {
@@ -1187,6 +1202,7 @@
mDisplayPowerProximityStateController.cleanup();
mBrightnessRangeController.stop();
mBrightnessThrottler.stop();
+ mBrightnessClamperController.stop();
mHandler.removeCallbacksAndMessages(null);
// Release any outstanding wakelocks we're still holding because of pending messages.
@@ -1257,14 +1273,6 @@
int state = mDisplayStateController
.updateDisplayState(mPowerRequest, mIsEnabled, mIsInTransition);
- if (mScreenOffBrightnessSensorController != null) {
- mScreenOffBrightnessSensorController
- .setLightSensorEnabled(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()
- && mIsEnabled && (state == Display.STATE_OFF || (state == Display.STATE_DOZE
- && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig()))
- && mLeadDisplayId == Layout.NO_LEAD_DISPLAY);
- }
-
// Initialize things the first time the power state is changed.
if (mustInitialize) {
initialize(readyToUpdateDisplayState() ? state : Display.STATE_UNKNOWN);
@@ -1290,6 +1298,17 @@
slowChange = mBrightnessToFollowSlowChange;
}
+ // Set up the ScreenOff controller used when coming out of SCREEN_OFF and the ALS sensor
+ // doesn't yet have a valid lux value to use with auto-brightness.
+ if (mScreenOffBrightnessSensorController != null) {
+ mScreenOffBrightnessSensorController
+ .setLightSensorEnabled(displayBrightnessState.getShouldUseAutoBrightness()
+ && mIsEnabled && (state == Display.STATE_OFF
+ || (state == Display.STATE_DOZE
+ && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig()))
+ && mLeadDisplayId == Layout.NO_LEAD_DISPLAY);
+ }
+
// Take note if the short term model was already active before applying the current
// request changes.
final boolean wasShortTermModelActive =
@@ -1519,6 +1538,8 @@
// allowed range.
float animateValue = clampScreenBrightness(brightnessState);
+ animateValue = mBrightnessClamperController.clamp(animateValue);
+
// If there are any HDR layers on the screen, we have a special brightness value that we
// use instead. We still preserve the calculated brightness for Standard Dynamic Range
// (SDR) layers, but the main brightness value will be the one for HDR.
@@ -1563,7 +1584,7 @@
notifyBrightnessTrackerChanged(brightnessState, userInitiatedChange,
wasShortTermModelActive, mAutomaticBrightnessStrategy.isAutoBrightnessEnabled(),
- brightnessIsTemporary);
+ brightnessIsTemporary, displayBrightnessState.getShouldUseAutoBrightness());
// We save the brightness info *after* the brightness setting has been changed and
// adjustments made so that the brightness info reflects the latest value.
@@ -1607,8 +1628,8 @@
mTempBrightnessEvent.setWasShortTermModelActive(wasShortTermModelActive);
mTempBrightnessEvent.setDisplayBrightnessStrategyName(displayBrightnessState
.getDisplayBrightnessStrategyName());
- mTempBrightnessEvent.setAutomaticBrightnessEnabled(mAutomaticBrightnessStrategy
- .shouldUseAutoBrightness());
+ mTempBrightnessEvent.setAutomaticBrightnessEnabled(
+ displayBrightnessState.getShouldUseAutoBrightness());
// Temporary is what we use during slider interactions. We avoid logging those so that
// we don't spam logcat when the slider is being used.
boolean tempToTempTransition =
@@ -2219,7 +2240,7 @@
private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated,
boolean wasShortTermModelActive, boolean autobrightnessEnabled,
- boolean brightnessIsTemporary) {
+ boolean brightnessIsTemporary, boolean shouldUseAutoBrightness) {
final float brightnessInNits =
mDisplayBrightnessController.convertToAdjustedNits(brightness);
@@ -2234,7 +2255,7 @@
|| mAutomaticBrightnessController.isInIdleMode()
|| !autobrightnessEnabled
|| mBrightnessTracker == null
- || !mAutomaticBrightnessStrategy.shouldUseAutoBrightness()
+ || !shouldUseAutoBrightness
|| brightnessInNits < 0.0f) {
return;
}
@@ -2411,6 +2432,11 @@
if (mDisplayStateController != null) {
mDisplayStateController.dumpsys(pw);
}
+
+ pw.println();
+ if (mBrightnessClamperController != null) {
+ mBrightnessClamperController.dump(ipw);
+ }
}
@@ -2916,6 +2942,10 @@
displayUniqueId, brightnessMin, brightnessMax, hbmData, hdrBrightnessCfg,
hbmChangeCallback, hbmMetadata, context);
}
+
+ boolean isColorFadeEnabled() {
+ return !ActivityManager.isLowRamDeviceStatic();
+ }
}
static class CachedBrightnessInfo {
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 2f52b70..ffd62a3 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -29,6 +29,7 @@
import com.android.server.display.AutomaticBrightnessController;
import com.android.server.display.BrightnessSetting;
import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
import java.io.PrintWriter;
@@ -134,11 +135,21 @@
public DisplayBrightnessState updateBrightness(
DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
int targetDisplayState) {
+
+ DisplayBrightnessState state;
synchronized (mLock) {
mDisplayBrightnessStrategy = mDisplayBrightnessStrategySelector.selectStrategy(
displayPowerRequest, targetDisplayState);
- return mDisplayBrightnessStrategy.updateBrightness(displayPowerRequest);
+ state = mDisplayBrightnessStrategy.updateBrightness(displayPowerRequest);
}
+
+ // This is a temporary measure until AutomaticBrightnessStrategy works as a traditional
+ // strategy.
+ // TODO: Remove when AutomaticBrightnessStrategy is populating the values directly.
+ if (state != null) {
+ state = addAutomaticBrightnessState(state);
+ }
+ return state;
}
/**
@@ -322,6 +333,13 @@
}
/**
+ * TODO(b/253226419): Remove once auto-brightness is a fully-functioning strategy.
+ */
+ public AutomaticBrightnessStrategy getAutomaticBrightnessStrategy() {
+ return mDisplayBrightnessStrategySelector.getAutomaticBrightnessStrategy();
+ }
+
+ /**
* Convert a brightness float scale value to a nit value. Adjustments, such as RBC, are not
* applied. This is used when storing the brightness in nits for the default display and when
* passing the brightness value to follower displays.
@@ -425,6 +443,18 @@
}
}
+ /**
+ * TODO(b/253226419): Remove once auto-brightness is a fully-functioning strategy.
+ */
+ private DisplayBrightnessState addAutomaticBrightnessState(DisplayBrightnessState state) {
+ AutomaticBrightnessStrategy autoStrat = getAutomaticBrightnessStrategy();
+
+ DisplayBrightnessState.Builder builder = DisplayBrightnessState.Builder.from(state);
+ builder.setShouldUseAutoBrightness(
+ autoStrat != null && autoStrat.shouldUseAutoBrightness());
+ return builder.build();
+ }
+
@GuardedBy("mLock")
private void setTemporaryBrightnessLocked(float temporaryBrightness) {
mDisplayBrightnessStrategySelector.getTemporaryDisplayBrightnessStrategy()
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index 02ca2d3..45f1be0 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -25,6 +25,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
@@ -60,6 +61,8 @@
private final FollowerBrightnessStrategy mFollowerBrightnessStrategy;
// The brightness strategy used to manage the brightness state when the request is invalid.
private final InvalidBrightnessStrategy mInvalidBrightnessStrategy;
+ // Controls brightness when automatic (adaptive) brightness is running.
+ private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy;
// We take note of the old brightness strategy so that we can know when the strategy changes.
private String mOldBrightnessStrategyName;
@@ -81,6 +84,7 @@
mBoostBrightnessStrategy = injector.getBoostBrightnessStrategy();
mFollowerBrightnessStrategy = injector.getFollowerBrightnessStrategy(displayId);
mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
+ mAutomaticBrightnessStrategy = injector.getAutomaticBrightnessStrategy(context, displayId);
mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
R.bool.config_allowAutoBrightnessWhileDozing);
mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName();
@@ -130,6 +134,10 @@
return mFollowerBrightnessStrategy;
}
+ public AutomaticBrightnessStrategy getAutomaticBrightnessStrategy() {
+ return mAutomaticBrightnessStrategy;
+ }
+
/**
* Returns a boolean flag indicating if the light sensor is to be used to decide the screen
* brightness when dozing
@@ -198,5 +206,9 @@
InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
return new InvalidBrightnessStrategy();
}
+
+ AutomaticBrightnessStrategy getAutomaticBrightnessStrategy(Context context, int displayId) {
+ return new AutomaticBrightnessStrategy(context, displayId);
+ }
}
}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
new file mode 100644
index 0000000..9345a3d
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamper.java
@@ -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.server.display.brightness.clamper;
+
+import android.annotation.NonNull;
+import android.os.PowerManager;
+
+import java.io.PrintWriter;
+
+abstract class BrightnessClamper<T> {
+
+ protected float mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
+ protected boolean mIsActive = false;
+
+ float getBrightnessCap() {
+ return mBrightnessCap;
+ }
+
+ boolean isActive() {
+ return mIsActive;
+ }
+
+ void dump(PrintWriter writer) {
+ writer.println("BrightnessClamper:" + getType());
+ writer.println(" mBrightnessCap: " + mBrightnessCap);
+ writer.println(" mIsActive: " + mIsActive);
+ }
+
+ @NonNull
+ abstract Type getType();
+
+ abstract void onDeviceConfigChanged();
+
+ abstract void onDisplayChanged(T displayData);
+
+ abstract void stop();
+
+ enum Type {
+ THERMAL
+ }
+}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
new file mode 100644
index 0000000..d0f28c3
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import static com.android.server.display.brightness.clamper.BrightnessClamper.Type;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.PowerManager;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfigInterface;
+import android.util.IndentingPrintWriter;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.DisplayDeviceConfig;
+import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
+import com.android.server.display.feature.DeviceConfigParameterProvider;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Clampers controller, all in DisplayControllerHandler
+ */
+public class BrightnessClamperController {
+
+ private static final boolean ENABLED = false;
+
+ private final DeviceConfigParameterProvider mDeviceConfigParameterProvider;
+ private final Handler mHandler;
+ private final ClamperChangeListener mClamperChangeListenerExternal;
+
+ private final Executor mExecutor;
+ private final List<BrightnessClamper<? super DisplayDeviceData>> mClampers = new ArrayList<>();
+ private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener =
+ properties -> mClampers.forEach(BrightnessClamper::onDeviceConfigChanged);
+ private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
+ @Nullable
+ private Type mClamperType = null;
+
+ public BrightnessClamperController(Handler handler,
+ ClamperChangeListener clamperChangeListener, DisplayDeviceData data) {
+ this(new Injector(), handler, clamperChangeListener, data);
+ }
+
+ @VisibleForTesting
+ BrightnessClamperController(Injector injector, Handler handler,
+ ClamperChangeListener clamperChangeListener, DisplayDeviceData data) {
+ mDeviceConfigParameterProvider = injector.getDeviceConfigParameterProvider();
+ mHandler = handler;
+ mClamperChangeListenerExternal = clamperChangeListener;
+ mExecutor = new HandlerExecutor(handler);
+
+ Runnable clamperChangeRunnableInternal = this::recalculateBrightnessCap;
+
+ ClamperChangeListener clamperChangeListenerInternal = () -> {
+ if (!mHandler.hasCallbacks(clamperChangeRunnableInternal)) {
+ mHandler.post(clamperChangeRunnableInternal);
+ }
+ };
+
+ if (ENABLED) {
+ mClampers.add(
+ new BrightnessThermalClamper(handler, clamperChangeListenerInternal, data));
+ start();
+ }
+ }
+
+ /**
+ * Should be called when display changed. Forwards the call to individual clampers
+ */
+ public void onDisplayChanged(DisplayDeviceData data) {
+ mClampers.forEach(clamper -> clamper.onDisplayChanged(data));
+ }
+
+ /**
+ * Applies clamping
+ * Called in DisplayControllerHandler
+ */
+ public float clamp(float value) {
+ return Math.min(value, mBrightnessCap);
+ }
+
+ /**
+ * Used to dump ClampersController state.
+ */
+ public void dump(PrintWriter writer) {
+ writer.println("BrightnessClampersController:");
+ writer.println(" mBrightnessCap: " + mBrightnessCap);
+ writer.println(" mClamperType: " + mClamperType);
+ IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
+ mClampers.forEach(clamper -> clamper.dump(ipw));
+ }
+
+ /**
+ * This method should be called when the ClamperController is no longer in use.
+ * Called in DisplayControllerHandler
+ */
+ public void stop() {
+ mDeviceConfigParameterProvider.removeOnPropertiesChangedListener(
+ mOnPropertiesChangedListener);
+ mClampers.forEach(BrightnessClamper::stop);
+ }
+
+
+ // Called in DisplayControllerHandler
+ private void recalculateBrightnessCap() {
+ float brightnessCap = PowerManager.BRIGHTNESS_MAX;
+ Type clamperType = null;
+
+ BrightnessClamper<?> minClamper = mClampers.stream()
+ .filter(BrightnessClamper::isActive)
+ .min((clamper1, clamper2) -> Float.compare(clamper1.getBrightnessCap(),
+ clamper2.getBrightnessCap())).orElse(null);
+
+ if (minClamper != null) {
+ brightnessCap = minClamper.getBrightnessCap();
+ clamperType = minClamper.getType();
+ }
+
+ if (mBrightnessCap != brightnessCap || mClamperType != clamperType) {
+ mBrightnessCap = brightnessCap;
+ mClamperType = clamperType;
+ mClamperChangeListenerExternal.onChanged();
+ }
+ }
+
+ private void start() {
+ mDeviceConfigParameterProvider.addOnPropertiesChangedListener(
+ mExecutor, mOnPropertiesChangedListener);
+ }
+
+ /**
+ * Clampers change listener
+ */
+ public interface ClamperChangeListener {
+ /**
+ * Notifies that clamper state changed
+ */
+ void onChanged();
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ DeviceConfigParameterProvider getDeviceConfigParameterProvider() {
+ return new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
+ }
+ }
+
+ /**
+ * Data for clampers
+ */
+ public static class DisplayDeviceData implements BrightnessThermalClamper.ThermalData {
+ @NonNull
+ private final String mUniqueDisplayId;
+ @NonNull
+ private final String mThermalThrottlingDataId;
+
+ private final DisplayDeviceConfig mDisplayDeviceConfig;
+
+ public DisplayDeviceData(@NonNull String uniqueDisplayId,
+ @NonNull String thermalThrottlingDataId,
+ @NonNull DisplayDeviceConfig displayDeviceConfig) {
+ mUniqueDisplayId = uniqueDisplayId;
+ mThermalThrottlingDataId = thermalThrottlingDataId;
+ mDisplayDeviceConfig = displayDeviceConfig;
+ }
+
+
+ @NonNull
+ @Override
+ public String getUniqueDisplayId() {
+ return mUniqueDisplayId;
+ }
+
+ @NonNull
+ @Override
+ public String getThermalThrottlingDataId() {
+ return mThermalThrottlingDataId;
+ }
+
+ @Nullable
+ @Override
+ public ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData() {
+ return mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId().get(
+ mThermalThrottlingDataId);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java
new file mode 100644
index 0000000..8ae962b
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessThermalClamper.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import static com.android.server.display.DisplayDeviceConfig.DEFAULT_ID;
+import static com.android.server.display.brightness.clamper.BrightnessClamperController.ClamperChangeListener;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.Temperature;
+import android.provider.DeviceConfigInterface;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
+import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
+import com.android.server.display.feature.DeviceConfigParameterProvider;
+import com.android.server.display.utils.DeviceConfigParsingUtils;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+
+class BrightnessThermalClamper extends
+ BrightnessClamper<BrightnessThermalClamper.ThermalData> {
+
+ private static final String TAG = "BrightnessThermalClamper";
+
+ @Nullable
+ private final IThermalService mThermalService;
+ @NonNull
+ private final DeviceConfigParameterProvider mConfigParameterProvider;
+ @NonNull
+ private final Handler mHandler;
+ @NonNull
+ private final ClamperChangeListener mChangelistener;
+ // data from DeviceConfig, for all displays, for all dataSets
+ // mapOf(uniqueDisplayId to mapOf(dataSetId to ThermalBrightnessThrottlingData))
+ @NonNull
+ private Map<String, Map<String, ThermalBrightnessThrottlingData>>
+ mThermalThrottlingDataOverride = Map.of();
+ // data from DisplayDeviceConfig, for particular display+dataSet
+ @Nullable
+ private ThermalBrightnessThrottlingData mThermalThrottlingDataFromDeviceConfig = null;
+ // Active data, if mDataOverride contains data for mUniqueDisplayId, mDataId, then use it,
+ // otherwise mDataFromDeviceConfig
+ @Nullable
+ private ThermalBrightnessThrottlingData mThermalThrottlingDataActive = null;
+ private boolean mStarted = false;
+ @Nullable
+ private String mUniqueDisplayId = null;
+ @Nullable
+ private String mDataId = null;
+ @Temperature.ThrottlingStatus
+ private int mThrottlingStatus = Temperature.THROTTLING_NONE;
+
+ private final IThermalEventListener mThermalEventListener = new IThermalEventListener.Stub() {
+ @Override
+ public void notifyThrottling(Temperature temperature) {
+ @Temperature.ThrottlingStatus int status = temperature.getStatus();
+ mHandler.post(() -> thermalStatusChanged(status));
+ }
+ };
+
+ private final BiFunction<String, String, ThrottlingLevel> mDataPointMapper = (key, value) -> {
+ try {
+ int status = DeviceConfigParsingUtils.parseThermalStatus(key);
+ float brightnessPoint = DeviceConfigParsingUtils.parseBrightness(value);
+ return new ThrottlingLevel(status, brightnessPoint);
+ } catch (IllegalArgumentException iae) {
+ return null;
+ }
+ };
+
+ private final Function<List<ThrottlingLevel>, ThermalBrightnessThrottlingData>
+ mDataSetMapper = ThermalBrightnessThrottlingData::create;
+
+
+ BrightnessThermalClamper(Handler handler, ClamperChangeListener listener,
+ ThermalData thermalData) {
+ this(new Injector(), handler, listener, thermalData);
+ }
+
+ @VisibleForTesting
+ BrightnessThermalClamper(Injector injector, Handler handler,
+ ClamperChangeListener listener, ThermalData thermalData) {
+ mThermalService = injector.getThermalService();
+ mConfigParameterProvider = injector.getDeviceConfigParameterProvider();
+ mHandler = handler;
+ mChangelistener = listener;
+ mHandler.post(() -> {
+ setDisplayData(thermalData);
+ loadOverrideData();
+ start();
+ });
+
+ }
+
+ @Override
+ @NonNull
+ Type getType() {
+ return Type.THERMAL;
+ }
+
+ @Override
+ void onDeviceConfigChanged() {
+ mHandler.post(() -> {
+ loadOverrideData();
+ recalculateActiveData();
+ });
+ }
+
+ @Override
+ void onDisplayChanged(ThermalData data) {
+ mHandler.post(() -> {
+ setDisplayData(data);
+ recalculateActiveData();
+ });
+ }
+
+ @Override
+ void stop() {
+ if (!mStarted) {
+ return;
+ }
+ try {
+ mThermalService.unregisterThermalEventListener(mThermalEventListener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to unregister thermal status listener", e);
+ }
+ mStarted = false;
+ }
+
+ @Override
+ void dump(PrintWriter writer) {
+ writer.println("BrightnessThermalClamper:");
+ writer.println(" mStarted: " + mStarted);
+ if (mThermalService != null) {
+ writer.println(" ThermalService available");
+ } else {
+ writer.println(" ThermalService not available");
+ }
+ writer.println(" mThrottlingStatus: " + mThrottlingStatus);
+ writer.println(" mUniqueDisplayId: " + mUniqueDisplayId);
+ writer.println(" mDataId: " + mDataId);
+ writer.println(" mDataOverride: " + mThermalThrottlingDataOverride);
+ writer.println(" mDataFromDeviceConfig: " + mThermalThrottlingDataFromDeviceConfig);
+ writer.println(" mDataActive: " + mThermalThrottlingDataActive);
+ super.dump(writer);
+ }
+
+ private void recalculateActiveData() {
+ if (mUniqueDisplayId == null || mDataId == null) {
+ return;
+ }
+ mThermalThrottlingDataActive = mThermalThrottlingDataOverride
+ .getOrDefault(mUniqueDisplayId, Map.of()).getOrDefault(mDataId,
+ mThermalThrottlingDataFromDeviceConfig);
+
+ recalculateBrightnessCap();
+ }
+
+ private void loadOverrideData() {
+ String throttlingDataOverride = mConfigParameterProvider.getBrightnessThrottlingData();
+ mThermalThrottlingDataOverride = DeviceConfigParsingUtils.parseDeviceConfigMap(
+ throttlingDataOverride, mDataPointMapper, mDataSetMapper);
+ }
+
+ private void setDisplayData(@NonNull ThermalData data) {
+ mUniqueDisplayId = data.getUniqueDisplayId();
+ mDataId = data.getThermalThrottlingDataId();
+ mThermalThrottlingDataFromDeviceConfig = data.getThermalBrightnessThrottlingData();
+ if (mThermalThrottlingDataFromDeviceConfig == null && !DEFAULT_ID.equals(mDataId)) {
+ Slog.wtf(TAG,
+ "Thermal throttling data is missing for thermalThrottlingDataId=" + mDataId);
+ }
+ }
+
+ private void recalculateBrightnessCap() {
+ float brightnessCap = PowerManager.BRIGHTNESS_MAX;
+ boolean isActive = false;
+
+ if (mThermalThrottlingDataActive != null) {
+ // Throttling levels are sorted by increasing severity
+ for (ThrottlingLevel level : mThermalThrottlingDataActive.throttlingLevels) {
+ if (level.thermalStatus <= mThrottlingStatus) {
+ brightnessCap = level.brightness;
+ isActive = true;
+ } else {
+ // Throttling levels that are greater than the current status are irrelevant
+ break;
+ }
+ }
+ }
+
+ if (brightnessCap != mBrightnessCap || mIsActive != isActive) {
+ mBrightnessCap = brightnessCap;
+ mIsActive = isActive;
+ mChangelistener.onChanged();
+ }
+ }
+
+ private void thermalStatusChanged(@Temperature.ThrottlingStatus int status) {
+ if (mThrottlingStatus != status) {
+ mThrottlingStatus = status;
+ recalculateBrightnessCap();
+ }
+ }
+
+ private void start() {
+ if (mThermalService == null) {
+ Slog.e(TAG, "Could not observe thermal status. Service not available");
+ return;
+ }
+ try {
+ // We get a callback immediately upon registering so there's no need to query
+ // for the current value.
+ mThermalService.registerThermalEventListenerWithType(mThermalEventListener,
+ Temperature.TYPE_SKIN);
+ mStarted = true;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register thermal status listener", e);
+ }
+ }
+
+ interface ThermalData {
+ @NonNull
+ String getUniqueDisplayId();
+
+ @NonNull
+ String getThermalThrottlingDataId();
+
+ @Nullable
+ ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData();
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ IThermalService getThermalService() {
+ return IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ }
+
+ DeviceConfigParameterProvider getDeviceConfigParameterProvider() {
+ return new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/display/utils/DeviceConfigParsingUtils.java b/services/core/java/com/android/server/display/utils/DeviceConfigParsingUtils.java
new file mode 100644
index 0000000..a8034c5
--- /dev/null
+++ b/services/core/java/com/android/server/display/utils/DeviceConfigParsingUtils.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.PowerManager;
+import android.util.Slog;
+
+import com.android.server.display.DisplayDeviceConfig;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * Provides utility methods for DeviceConfig string parsing
+ */
+public class DeviceConfigParsingUtils {
+ private static final String TAG = "DeviceConfigParsingUtils";
+
+ /**
+ * Parses map from device config
+ * Data format:
+ * (displayId:String,numberOfPoints:Int,(state:T,value:Float){numberOfPoints},
+ * dataSetId:String)?;)+
+ * result : mapOf(displayId to mapOf(dataSetId to V))
+ */
+ @NonNull
+ public static <T, V> Map<String, Map<String, V>> parseDeviceConfigMap(
+ @Nullable String data,
+ @NonNull BiFunction<String, String, T> dataPointMapper,
+ @NonNull Function<List<T>, V> dataSetMapper) {
+ if (data == null) {
+ return Map.of();
+ }
+ Map<String, Map<String, V>> result = new HashMap<>();
+ String[] dataSets = data.split(";"); // by displayId + dataSetId
+ for (String dataSet : dataSets) {
+ String[] items = dataSet.split(",");
+ int noOfItems = items.length;
+ // Validate number of items, at least: displayId,1,key1,value1
+ if (noOfItems < 4) {
+ Slog.e(TAG, "Invalid dataSet(not enough items):" + dataSet, new Throwable());
+ return Map.of();
+ }
+ int i = 0;
+ String uniqueDisplayId = items[i++];
+
+ String numberOfPointsString = items[i++];
+ int numberOfPoints;
+ try {
+ numberOfPoints = Integer.parseInt(numberOfPointsString);
+ } catch (NumberFormatException nfe) {
+ Slog.e(TAG, "Invalid dataSet(invalid number of points):" + dataSet, nfe);
+ return Map.of();
+ }
+ // Validate number of itmes based on numberOfPoints:
+ // displayId,numberOfPoints,(key,value) x numberOfPoints,dataSetId(optional)
+ int expectedMinItems = 2 + numberOfPoints * 2;
+ if (noOfItems < expectedMinItems || noOfItems > expectedMinItems + 1) {
+ Slog.e(TAG, "Invalid dataSet(wrong number of points):" + dataSet, new Throwable());
+ return Map.of();
+ }
+ // Construct data points
+ List<T> dataPoints = new ArrayList<>();
+ for (int j = 0; j < numberOfPoints; j++) {
+ String key = items[i++];
+ String value = items[i++];
+ T dataPoint = dataPointMapper.apply(key, value);
+ if (dataPoint == null) {
+ Slog.e(TAG,
+ "Invalid dataPoint ,key=" + key + ",value=" + value + ",dataSet="
+ + dataSet, new Throwable());
+ return Map.of();
+ }
+ dataPoints.add(dataPoint);
+ }
+ // Construct dataSet
+ V dataSetMapped = dataSetMapper.apply(dataPoints);
+ if (dataSetMapped == null) {
+ Slog.e(TAG, "Invalid dataSetMapped dataPoints=" + dataPoints + ",dataSet="
+ + dataSet, new Throwable());
+ return Map.of();
+ }
+ // Get dataSetId and dataSets map for displayId
+ String dataSetId = (i < items.length) ? items[i] : DisplayDeviceConfig.DEFAULT_ID;
+ Map<String, V> byDisplayId = result.computeIfAbsent(uniqueDisplayId,
+ k -> new HashMap<>());
+
+ // Try to store dataSet in datasets for display
+ if (byDisplayId.put(dataSetId, dataSetMapped) != null) {
+ Slog.e(TAG, "Duplicate dataSetId=" + dataSetId + ",data=" + data, new Throwable());
+ return Map.of();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Parses thermal string value from device config
+ */
+ @PowerManager.ThermalStatus
+ public static int parseThermalStatus(@NonNull String value) throws IllegalArgumentException {
+ switch (value) {
+ case "none":
+ return PowerManager.THERMAL_STATUS_NONE;
+ case "light":
+ return PowerManager.THERMAL_STATUS_LIGHT;
+ case "moderate":
+ return PowerManager.THERMAL_STATUS_MODERATE;
+ case "severe":
+ return PowerManager.THERMAL_STATUS_SEVERE;
+ case "critical":
+ return PowerManager.THERMAL_STATUS_CRITICAL;
+ case "emergency":
+ return PowerManager.THERMAL_STATUS_EMERGENCY;
+ case "shutdown":
+ return PowerManager.THERMAL_STATUS_SHUTDOWN;
+ default:
+ throw new IllegalArgumentException("Invalid Thermal Status: " + value);
+ }
+ }
+
+ /**
+ * Parses brightness value from device config
+ */
+ public static float parseBrightness(String stringVal) throws IllegalArgumentException {
+ float value = Float.parseFloat(stringVal);
+ if (value < PowerManager.BRIGHTNESS_MIN || value > PowerManager.BRIGHTNESS_MAX) {
+ throw new IllegalArgumentException("Brightness value out of bounds: " + stringVal);
+ }
+ return value;
+ }
+}
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 6368a7b..7a8de34 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -29,6 +29,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;
@@ -1169,6 +1170,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/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 02ee96a..7bda2c1 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1175,6 +1175,8 @@
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
+ resolver.registerContentObserver(Settings.Secure.getUriFor(
+ STYLUS_HANDWRITING_ENABLED), false, this);
mRegistered = true;
}
@@ -1183,6 +1185,8 @@
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+ final Uri stylusHandwritingEnabledUri = Settings.Secure.getUriFor(
+ STYLUS_HANDWRITING_ENABLED);
synchronized (ImfLock.class) {
if (showImeUri.equals(uri)) {
mMenuController.updateKeyboardFromSettingsLocked();
@@ -1200,6 +1204,8 @@
showCurrentInputImplicitLocked(mCurFocusedWindow,
SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE);
}
+ } else if (stylusHandwritingEnabledUri.equals(uri)) {
+ InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
} else {
boolean enabledChanged = false;
String newEnabled = mSettings.getEnabledInputMethodsStr();
@@ -2363,7 +2369,7 @@
mCurVirtualDisplayToScreenMatrix = null;
ImeTracker.forLogging().onFailed(mCurStatsToken, ImeTracker.PHASE_SERVER_WAIT_IME);
mCurStatsToken = null;
-
+ InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
mMenuController.hideInputMethodMenuLocked();
}
}
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 12fc263..5dd958b 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1371,7 +1371,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);
}
@@ -1758,6 +1760,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 d093393..6df3809 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -322,7 +322,6 @@
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.PermissionPolicyInternal;
-import com.android.server.powerstats.StatsPullAtomCallbackImpl;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.utils.Slogf;
@@ -1715,7 +1714,6 @@
return;
}
- boolean queryRestart = false;
boolean queryRemove = false;
boolean packageChanged = false;
boolean cancelNotifications = true;
@@ -1727,7 +1725,6 @@
|| (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
|| (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
- || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
|| action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
|| action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
@@ -1768,10 +1765,6 @@
cancelNotifications = false;
unhideNotifications = true;
}
-
- } else if (queryRestart) {
- pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
- uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
} else {
Uri uri = intent.getData();
if (uri == null) {
@@ -1809,7 +1802,7 @@
if (cancelNotifications) {
for (String pkgName : pkgList) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
- !queryRestart, changeUserId, reason, null);
+ changeUserId, reason);
}
} else if (hideNotifications && uidList != null && (uidList.length > 0)) {
hideNotificationsForPackages(pkgList, uidList);
@@ -1843,14 +1836,14 @@
} else if (action.equals(Intent.ACTION_USER_STOPPED)) {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0) {
- cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
- REASON_USER_STOPPED, null);
+ cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
+ REASON_USER_STOPPED);
}
} else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0 && !mDpm.isKeepProfilesRunningEnabled()) {
- cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
- REASON_PROFILE_TURNED_OFF, null);
+ cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, userHandle,
+ REASON_PROFILE_TURNED_OFF);
mSnoozeHelper.clearData(userHandle);
}
} else if (action.equals(Intent.ACTION_USER_PRESENT)) {
@@ -2468,7 +2461,6 @@
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
pkgFilter.addDataScheme("package");
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
null);
@@ -2499,6 +2491,16 @@
getContext().registerReceiver(mReviewNotificationPermissionsReceiver,
ReviewNotificationPermissionsReceiver.getFilter(),
Context.RECEIVER_NOT_EXPORTED);
+
+ mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null,
+ new AppOpsManager.OnOpChangedInternalListener() {
+ @Override
+ public void onOpChanged(@NonNull String op, @NonNull String packageName,
+ int userId) {
+ mHandler.post(
+ () -> handleNotificationPermissionChange(packageName, userId));
+ }
+ });
}
/**
@@ -2855,17 +2857,17 @@
boolean fromListener) {
if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
// cancel
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
- UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
- null);
+ cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0,
+ UserHandle.getUserId(uid), REASON_CHANNEL_BANNED
+ );
if (isUidSystemOrPhone(uid)) {
IntArray profileIds = mUserProfiles.getCurrentProfileIds();
int N = profileIds.size();
for (int i = 0; i < N; i++) {
int profileId = profileIds.get(i);
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
- profileId, REASON_CHANNEL_BANNED,
- null);
+ cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0,
+ profileId, REASON_CHANNEL_BANNED
+ );
}
}
}
@@ -3539,7 +3541,7 @@
// Don't allow the app to cancel active FGS or UIJ notifications
cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
pkg, null, 0, FLAG_FOREGROUND_SERVICE | FLAG_USER_INITIATED_JOB,
- true, userId, REASON_APP_CANCEL_ALL, null);
+ userId, REASON_APP_CANCEL_ALL);
}
@Override
@@ -3558,20 +3560,16 @@
}
mPermissionHelper.setNotificationPermission(
pkg, UserHandle.getUserId(uid), enabled, true);
- sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
.setType(MetricsEvent.TYPE_ACTION)
.setPackageName(pkg)
.setSubtype(enabled ? 1 : 0));
mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled);
- // Now, cancel any outstanding notifications that are part of a just-disabled app
- if (!enabled) {
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
- UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
- }
- handleSavePolicyFile();
+ // Outstanding notifications from this package will be cancelled, and the package will
+ // be sent the ACTION_APP_BLOCK_STATE_CHANGED broadcast, as soon as we get the
+ // callback from AppOpsManager.
}
/**
@@ -4030,8 +4028,8 @@
}
enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
enforceDeletingChannelHasNoUserInitiatedJob(pkg, callingUser, channelId);
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
- callingUser, REASON_CHANNEL_REMOVED, null);
+ cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
+ callingUser, REASON_CHANNEL_REMOVED);
boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel(
pkg, callingUid, channelId, callingUid, isSystemOrSystemUi);
if (previouslyExisted) {
@@ -4085,9 +4083,8 @@
for (int i = 0; i < deletedChannels.size(); i++) {
final NotificationChannel deletedChannel = deletedChannels.get(i);
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
- true,
- userId, REASON_CHANNEL_REMOVED,
- null);
+ userId, REASON_CHANNEL_REMOVED
+ );
mListeners.notifyNotificationChannelChanged(pkg,
UserHandle.getUserHandleForUid(callingUid),
deletedChannel,
@@ -4256,8 +4253,8 @@
checkCallerIsSystem();
// Cancel posted notifications
final int userId = UserHandle.getUserId(uid);
- cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
- UserHandle.getUserId(Binder.getCallingUid()), REASON_CLEAR_DATA, null);
+ cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0,
+ UserHandle.getUserId(Binder.getCallingUid()), REASON_CLEAR_DATA);
// Zen
packagesChanged |=
@@ -5895,6 +5892,21 @@
}
};
+ private void handleNotificationPermissionChange(String pkg, @UserIdInt int userId) {
+ int uid = mPackageManagerInternal.getPackageUid(pkg, 0, userId);
+ if (uid == INVALID_UID) {
+ Log.e(TAG, String.format("No uid found for %s, %s!", pkg, userId));
+ return;
+ }
+ boolean hasPermission = mPermissionHelper.hasPermission(uid);
+ sendAppBlockStateChangedBroadcast(pkg, uid, !hasPermission);
+ if (!hasPermission) {
+ cancelAllNotificationsInt(MY_UID, MY_PID, pkg, /* channelId= */ null,
+ /* mustHaveFlags= */ 0, /* mustNotHaveFlags= */ 0, userId,
+ REASON_PACKAGE_BANNED);
+ }
+ }
+
protected void checkNotificationListenerAccess() {
if (!isCallerSystemOrPhone()) {
getContext().enforceCallingPermission(
@@ -6831,9 +6843,9 @@
mPreferencesHelper.deleteConversations(pkg, uid, shortcuts,
/* callingUid */ Process.SYSTEM_UID, /* is system */ true);
for (String channelId : deletedChannelIds) {
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
- UserHandle.getUserId(uid), REASON_CHANNEL_REMOVED,
- null);
+ cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0,
+ UserHandle.getUserId(uid), REASON_CHANNEL_REMOVED
+ );
}
handleSavePolicyFile();
}
@@ -7008,7 +7020,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);
}
@@ -9535,25 +9547,18 @@
/**
* Cancels all notifications from a given package that have all of the
- * {@code mustHaveFlags}.
+ * {@code mustHaveFlags} and none of the {@code mustNotHaveFlags}.
*/
- void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
- int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
- ManagedServiceInfo listener) {
+ void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg,
+ @Nullable String channelId, int mustHaveFlags, int mustNotHaveFlags, int userId,
+ int reason) {
final long cancellationElapsedTimeMs = SystemClock.elapsedRealtime();
mHandler.post(new Runnable() {
@Override
public void run() {
- String listenerName = listener == null ? null : listener.component.toShortString();
EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
- listenerName);
-
- // Why does this parameter exist? Do we actually want to execute the above if doit
- // is false?
- if (!doit) {
- return;
- }
+ /* listener= */ null);
synchronized (mNotificationLock) {
FlagChecker flagChecker = (int flags) -> {
@@ -9565,14 +9570,15 @@
}
return true;
};
- cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
- pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
+ cancelAllNotificationsByListLocked(mNotificationList, pkg,
+ true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
- listenerName, true /* wasPosted */, cancellationElapsedTimeMs);
- cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
- callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
- flagChecker, false /*includeCurrentProfiles*/, userId,
- false /*sendDelete*/, reason, listenerName, false /* wasPosted */,
+ null /* listenerName */, true /* wasPosted */,
+ cancellationElapsedTimeMs);
+ cancelAllNotificationsByListLocked(mEnqueuedNotifications, pkg,
+ true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
+ false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
+ null /* listenerName */, false /* wasPosted */,
cancellationElapsedTimeMs);
mSnoozeHelper.cancel(userId, pkg);
}
@@ -9587,9 +9593,9 @@
@GuardedBy("mNotificationLock")
private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
- int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
- String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
- boolean sendDelete, int reason, String listenerName, boolean wasPosted,
+ @Nullable String pkg, boolean nullPkgIndicatesUserSwitch, @Nullable String channelId,
+ FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, boolean sendDelete,
+ int reason, String listenerName, boolean wasPosted,
@ElapsedRealtimeLong long cancellationElapsedTimeMs) {
Set<String> childNotifications = null;
for (int i = notificationList.size() - 1; i >= 0; --i) {
@@ -9706,12 +9712,12 @@
return true;
};
- cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
+ cancelAllNotificationsByListLocked(mNotificationList,
null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
includeCurrentProfiles, userId, true /*sendDelete*/, reason,
listenerName, true, cancellationElapsedTimeMs);
- cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
- callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
+ cancelAllNotificationsByListLocked(mEnqueuedNotifications,
+ null, false /*nullPkgIndicatesUserSwitch*/, null,
flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
reason, listenerName, false, cancellationElapsedTimeMs);
mSnoozeHelper.cancel(userId, includeCurrentProfiles);
@@ -10504,6 +10510,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;
@@ -11048,6 +11059,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/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 279a480..5cfbcaa 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3211,8 +3211,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:
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0994fa4..dd6bcb1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5660,13 +5660,6 @@
final DisplayContent displayContent = getDisplayContent();
if (!visible) {
mImeInsetsFrozenUntilStartInput = true;
- if (usingShellTransitions) {
- final WindowState wallpaperTarget =
- displayContent.mWallpaperController.getWallpaperTarget();
- if (wallpaperTarget != null && wallpaperTarget.mActivityRecord == this) {
- displayContent.mWallpaperController.hideWallpapers(wallpaperTarget);
- }
- }
}
if (!displayContent.mClosingApps.contains(this)
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 4262e94e..884100c 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1591,6 +1591,9 @@
if (forceTransientTransition) {
transitionController.collect(mLastStartActivityRecord);
transitionController.collect(mPriorAboveTask);
+ // If keyguard is active and occluded, the transient target won't be moved to front
+ // to be collected, so set transient again after it is collected.
+ transitionController.setTransientLaunch(mLastStartActivityRecord, mPriorAboveTask);
final DisplayContent dc = mLastStartActivityRecord.getDisplayContent();
// update wallpaper target to TransientHide
dc.mWallpaperController.adjustWallpaperWindows();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 738797b..50948e1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2186,7 +2186,7 @@
* Processes the activities to be stopped or destroyed. This should be called when the resumed
* activities are idle or drawn.
*/
- private void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,
+ void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,
boolean processPausingActivities, String reason) {
// Stop any activities that are scheduled to do so but have been waiting for the transition
// animation to finish.
@@ -2194,7 +2194,10 @@
ArrayList<ActivityRecord> readyToStopActivities = null;
for (int i = 0; i < mStoppingActivities.size(); i++) {
final ActivityRecord s = mStoppingActivities.get(i);
- final boolean animating = s.isInTransition();
+ // Activity in a force hidden task should not be counted as animating, i.e., we want to
+ // send onStop before any configuration change when removing pip transition is ongoing.
+ final boolean animating = s.isInTransition()
+ && s.getTask() != null && !s.getTask().isForceHidden();
displaySwapping |= s.isDisplaySleepingAndSwapping();
ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
+ "finishing=%s", s, s.nowVisible, animating, s.finishing);
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 0115877..4ce21bd 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -93,15 +93,12 @@
/** Whether the start transaction of the transition is committed (by shell). */
private boolean mIsStartTransactionCommitted;
- /** Whether all windows should wait for the start transaction. */
- private boolean mAlwaysWaitForStartTransaction;
-
/** Whether the target windows have been requested to sync their draw transactions. */
private boolean mIsSyncDrawRequested;
private SeamlessRotator mRotator;
- private final int mOriginalRotation;
+ private int mOriginalRotation;
private final boolean mHasScreenRotationAnimation;
AsyncRotationController(DisplayContent displayContent) {
@@ -147,15 +144,6 @@
if (mTransitionOp == OP_LEGACY) {
mIsStartTransactionCommitted = true;
} else if (displayContent.mTransitionController.isCollecting(displayContent)) {
- final Transition transition =
- mDisplayContent.mTransitionController.getCollectingTransition();
- if (transition != null) {
- final BLASTSyncEngine.SyncGroup syncGroup =
- mDisplayContent.mWmService.mSyncEngine.getSyncSet(transition.getSyncId());
- if (syncGroup != null && syncGroup.mSyncMethod == BLASTSyncEngine.METHOD_BLAST) {
- mAlwaysWaitForStartTransaction = true;
- }
- }
keepAppearanceInPreviousRotation();
}
}
@@ -279,10 +267,12 @@
// The previous animation leash will be dropped when preparing fade-in animation, so
// simply apply new animation without restoring the transformation.
fadeWindowToken(true /* show */, windowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
- } else if (op.mAction == Operation.ACTION_SEAMLESS && mRotator != null
+ } else if (op.mAction == Operation.ACTION_SEAMLESS
&& op.mLeash != null && op.mLeash.isValid()) {
if (DEBUG) Slog.d(TAG, "finishOp undo seamless " + windowToken.getTopChild());
- mRotator.setIdentityMatrix(windowToken.getSyncTransaction(), op.mLeash);
+ final SurfaceControl.Transaction t = windowToken.getSyncTransaction();
+ t.setMatrix(op.mLeash, 1, 0, 0, 1);
+ t.setPosition(op.mLeash, 0, 0);
}
}
@@ -365,6 +355,32 @@
}
}
+ /**
+ * Re-initialize the states if the current display rotation has changed to a different rotation.
+ * This is mainly for seamless rotation to update the transform based on new rotation.
+ */
+ void updateRotation() {
+ if (mRotator == null) return;
+ final int currentRotation = mDisplayContent.getWindowConfiguration().getRotation();
+ if (mOriginalRotation == currentRotation) {
+ return;
+ }
+ Slog.d(TAG, "Update original rotation " + currentRotation);
+ mOriginalRotation = currentRotation;
+ mDisplayContent.forAllWindows(w -> {
+ if (w.mForceSeamlesslyRotate && w.mHasSurface
+ && !mTargetWindowTokens.containsKey(w.mToken)) {
+ final Operation op = new Operation(Operation.ACTION_SEAMLESS);
+ op.mLeash = w.mToken.mSurfaceControl;
+ mTargetWindowTokens.put(w.mToken, op);
+ }
+ }, true /* traverseTopToBottom */);
+ mRotator = null;
+ mIsStartTransactionCommitted = false;
+ mIsSyncDrawRequested = false;
+ keepAppearanceInPreviousRotation();
+ }
+
private void scheduleTimeout() {
if (mTimeoutRunnable == null) {
mTimeoutRunnable = () -> {
@@ -589,7 +605,7 @@
* start transaction of rotation transition is applied.
*/
private boolean canDrawBeforeStartTransaction(Operation op) {
- return !mAlwaysWaitForStartTransaction && op.mAction != Operation.ACTION_SEAMLESS;
+ return op.mAction != Operation.ACTION_SEAMLESS;
}
/** The operation to control the rotation appearance associated with window token. */
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index b216578..188f4d0 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -280,7 +280,7 @@
// visible window.
if (Process.isSdkSandboxUid(realCallingUid)) {
int realCallingSdkSandboxUidToAppUid =
- Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
+ Process.getAppUidForSdkSandboxUid(realCallingUid);
if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
return logStartAllowedAndReturnCode(BAL_ALLOW_SDK_SANDBOX,
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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index bfd2a10..cb7414e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3457,6 +3457,11 @@
this, this, null /* remoteTransition */, displayChange);
if (t != null) {
mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
+ if (mAsyncRotationController != null) {
+ // Give a chance to update the transform if the current rotation is changed when
+ // some windows haven't finished previous rotation.
+ mAsyncRotationController.updateRotation();
+ }
if (mFixedRotationLaunchingApp != null) {
// A fixed-rotation transition is done, then continue to start a seamless display
// transition.
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/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/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index db3b267..71192cd 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -723,6 +723,14 @@
mFlags |= WindowManager.TRANSIT_FLAG_INVISIBLE;
return;
}
+ // Activity doesn't need to capture snapshot if the starting window has associated to task.
+ if (wc.asActivityRecord() != null) {
+ final ActivityRecord activityRecord = wc.asActivityRecord();
+ if (activityRecord.mStartingData != null
+ && activityRecord.mStartingData.mAssociatedTask != null) {
+ return;
+ }
+ }
if (mContainerFreezer == null) {
mContainerFreezer = new ScreenshotFreezer();
@@ -1183,16 +1191,6 @@
hasParticipatedDisplay = true;
continue;
}
- final WallpaperWindowToken wt = participant.asWallpaperToken();
- if (wt != null) {
- final boolean visibleAtTransitionEnd = mVisibleAtTransitionEndTokens.contains(wt);
- if (!visibleAtTransitionEnd && !wt.isVisibleRequested()) {
- ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
- " Commit wallpaper becoming invisible: %s", wt);
- wt.commitVisibility(false /* visible */);
- }
- continue;
- }
final Task tr = participant.asTask();
if (tr != null && tr.isVisibleRequested() && tr.inPinnedWindowingMode()) {
final ActivityRecord top = tr.getTopNonFinishingActivity();
@@ -1212,6 +1210,20 @@
}
}
}
+ // Commit wallpaper visibility after activity, because usually the wallpaper target token is
+ // an activity, and wallpaper's visibility is depends on activity's visibility.
+ for (int i = mParticipants.size() - 1; i >= 0; --i) {
+ final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
+ if (wt == null) continue;
+ final WindowState target = wt.mDisplayContent.mWallpaperController.getWallpaperTarget();
+ final boolean isTargetInvisible = target == null || !target.mToken.isVisible();
+ if (isTargetInvisible || (!wt.isVisibleRequested()
+ && !mVisibleAtTransitionEndTokens.contains(wt))) {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Commit wallpaper becoming invisible: %s", wt);
+ wt.commitVisibility(false /* visible */);
+ }
+ }
if (committedSomeInvisible) {
mController.onCommittedInvisibles();
}
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 d1b00a3..541fa94 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -24,6 +24,7 @@
import static android.window.TaskFragmentOperation.OP_TYPE_CLEAR_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
@@ -568,6 +569,13 @@
}
if (forceHiddenForPip) {
wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
+ // When removing pip, make sure that onStop is sent to the app ahead of
+ // onPictureInPictureModeChanged.
+ // See also PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismiss
+ wc.asTask().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ wc.asTask().mTaskSupervisor.processStoppingAndFinishingActivities(
+ null /* launchedActivity */, false /* processPausingActivities */,
+ "force-stop-on-removing-pip");
}
int containerEffect = applyWindowContainerChange(wc, entry.getValue(),
@@ -1335,6 +1343,19 @@
taskFragment.setAnimationParams(animationParams);
break;
}
+ case OP_TYPE_REORDER_TO_FRONT: {
+ final Task task = taskFragment.getTask();
+ if (task != null) {
+ final TaskFragment topTaskFragment = task.getTaskFragment(
+ tf -> tf.asTask() == null);
+ if (topTaskFragment != null && topTaskFragment != taskFragment) {
+ final int index = task.mChildren.indexOf(topTaskFragment);
+ task.mChildren.remove(taskFragment);
+ task.mChildren.add(index, taskFragment);
+ }
+ }
+ break;
+ }
}
return effects;
}
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 991248a..6960da7 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -434,6 +434,10 @@
+ "OnDevicePersonalizationSystemService$Lifecycle";
private static final String UPDATABLE_DEVICE_CONFIG_SERVICE_CLASS =
"com.android.server.deviceconfig.DeviceConfigInit$Lifecycle";
+ private static final String DEVICE_LOCK_SERVICE_CLASS =
+ "com.android.server.devicelock.DeviceLockService";
+ private static final String DEVICE_LOCK_APEX_PATH =
+ "/apex/com.android.devicelock/javalib/service-devicelock.jar";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -2864,6 +2868,13 @@
mSystemServiceManager.startService(HEALTHCONNECT_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_LOCK)) {
+ t.traceBegin("DeviceLockService");
+ mSystemServiceManager.startServiceFromJar(DEVICE_LOCK_SERVICE_CLASS,
+ DEVICE_LOCK_APEX_PATH);
+ t.traceEnd();
+ }
+
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
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/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/OWNERS b/services/tests/displayservicetests/OWNERS
similarity index 100%
rename from services/tests/displayservicetests/src/com/android/server/display/OWNERS
rename to services/tests/displayservicetests/OWNERS
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index a9e616d..8497dab 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -18,17 +18,23 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.res.Resources;
import android.hardware.display.DisplayManagerInternal;
import android.view.Display;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
@@ -38,6 +44,7 @@
import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -64,15 +71,20 @@
@Mock
private FollowerBrightnessStrategy mFollowerBrightnessStrategy;
@Mock
- private Context mContext;
- @Mock
private Resources mResources;
private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector;
+ private Context mContext;
+
+ @Rule
+ public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
@Before
public void before() {
MockitoAnnotations.initMocks(this);
+ mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
+ ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContext);
+ when(mContext.getContentResolver()).thenReturn(contentResolver);
when(mContext.getResources()).thenReturn(mResources);
when(mInvalidBrightnessStrategy.getName()).thenReturn("InvalidBrightnessStrategy");
DisplayBrightnessStrategySelector.Injector injector =
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java
new file mode 100644
index 0000000..37d0f62
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessThermalClamperTest.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.clamper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.display.DisplayManager;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.Temperature;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.Keep;
+import com.android.server.display.DisplayDeviceConfig;
+import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
+import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
+import com.android.server.display.feature.DeviceConfigParameterProvider;
+import com.android.server.testutils.FakeDeviceConfigInterface;
+import com.android.server.testutils.TestHandler;
+
+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 java.util.List;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+@RunWith(JUnitParamsRunner.class)
+public class BrightnessThermalClamperTest {
+
+ private static final float FLOAT_TOLERANCE = 0.001f;
+
+ private static final String DISPLAY_ID = "displayId";
+ @Mock
+ private IThermalService mMockThermalService;
+ @Mock
+ private BrightnessClamperController.ClamperChangeListener mMockClamperChangeListener;
+
+ private final FakeDeviceConfigInterface mFakeDeviceConfigInterface =
+ new FakeDeviceConfigInterface();
+ private final TestHandler mTestHandler = new TestHandler(null);
+ private BrightnessThermalClamper mClamper;
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mClamper = new BrightnessThermalClamper(new TestInjector(), mTestHandler,
+ mMockClamperChangeListener, new TestThermalData());
+ mTestHandler.flush();
+ }
+
+ @Test
+ public void testTypeIsThermal() {
+ assertEquals(BrightnessClamper.Type.THERMAL, mClamper.getType());
+ }
+
+ @Test
+ public void testNoThrottlingData() {
+ assertFalse(mClamper.isActive());
+ assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+ }
+
+ @Keep
+ private static Object[][] testThrottlingData() {
+ // throttlingLevels, throttlingStatus, expectedActive, expectedBrightness
+ return new Object[][] {
+ // no throttling data
+ {List.of(), Temperature.THROTTLING_LIGHT, false, PowerManager.BRIGHTNESS_MAX},
+ // throttlingStatus < min throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_LIGHT, false, PowerManager.BRIGHTNESS_MAX},
+ // throttlingStatus = min throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_MODERATE, true, 0.5f},
+ // throttlingStatus between min and max throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_SEVERE, true, 0.5f},
+ // throttlingStatus = max throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_CRITICAL, true, 0.1f},
+ // throttlingStatus > max throttling data
+ {List.of(
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_MODERATE, 0.5f),
+ new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL, 0.1f)),
+ Temperature.THROTTLING_EMERGENCY, true, 0.1f},
+ };
+ }
+ @Test
+ @Parameters(method = "testThrottlingData")
+ public void testNotifyThrottlingAfterOnDisplayChange(List<ThrottlingLevel> throttlingLevels,
+ @Temperature.ThrottlingStatus int throttlingStatus,
+ boolean expectedActive, float expectedBrightness) throws RemoteException {
+ IThermalEventListener thermalEventListener = captureThermalEventListener();
+ mClamper.onDisplayChanged(new TestThermalData(throttlingLevels));
+ mTestHandler.flush();
+ assertFalse(mClamper.isActive());
+ assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+
+ thermalEventListener.notifyThrottling(createTemperature(throttlingStatus));
+ mTestHandler.flush();
+ assertEquals(expectedActive, mClamper.isActive());
+ assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ @Parameters(method = "testThrottlingData")
+ public void testOnDisplayChangeAfterNotifyThrottlng(List<ThrottlingLevel> throttlingLevels,
+ @Temperature.ThrottlingStatus int throttlingStatus,
+ boolean expectedActive, float expectedBrightness) throws RemoteException {
+ IThermalEventListener thermalEventListener = captureThermalEventListener();
+ thermalEventListener.notifyThrottling(createTemperature(throttlingStatus));
+ mTestHandler.flush();
+ assertFalse(mClamper.isActive());
+ assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+
+ mClamper.onDisplayChanged(new TestThermalData(throttlingLevels));
+ mTestHandler.flush();
+ assertEquals(expectedActive, mClamper.isActive());
+ assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testOverrideData() throws RemoteException {
+ IThermalEventListener thermalEventListener = captureThermalEventListener();
+ thermalEventListener.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
+ mTestHandler.flush();
+ assertFalse(mClamper.isActive());
+ assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+
+ mClamper.onDisplayChanged(new TestThermalData(
+ List.of(new ThrottlingLevel(PowerManager.THERMAL_STATUS_SEVERE, 0.5f))));
+ mTestHandler.flush();
+ assertTrue(mClamper.isActive());
+ assertEquals(0.5f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+
+ overrideThrottlingData("displayId,1,emergency,0.4");
+ mClamper.onDeviceConfigChanged();
+ mTestHandler.flush();
+
+ assertFalse(mClamper.isActive());
+ assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+
+ overrideThrottlingData("displayId,1,moderate,0.4");
+ mClamper.onDeviceConfigChanged();
+ mTestHandler.flush();
+
+ assertTrue(mClamper.isActive());
+ assertEquals(0.4f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
+ }
+
+ private IThermalEventListener captureThermalEventListener() throws RemoteException {
+ ArgumentCaptor<IThermalEventListener> captor = ArgumentCaptor.forClass(
+ IThermalEventListener.class);
+ verify(mMockThermalService).registerThermalEventListenerWithType(captor.capture(), eq(
+ Temperature.TYPE_SKIN));
+ return captor.getValue();
+ }
+
+ private Temperature createTemperature(@Temperature.ThrottlingStatus int status) {
+ return new Temperature(100, Temperature.TYPE_SKIN, "test_temperature", status);
+ }
+
+ private void overrideThrottlingData(String data) {
+ mFakeDeviceConfigInterface.putProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_BRIGHTNESS_THROTTLING_DATA, data);
+ }
+
+ private class TestInjector extends BrightnessThermalClamper.Injector {
+ @Override
+ IThermalService getThermalService() {
+ return mMockThermalService;
+ }
+
+ @Override
+ DeviceConfigParameterProvider getDeviceConfigParameterProvider() {
+ return new DeviceConfigParameterProvider(mFakeDeviceConfigInterface);
+ }
+ }
+
+ private static class TestThermalData implements BrightnessThermalClamper.ThermalData {
+
+ private final String mUniqueDisplayId;
+ private final String mDataId;
+ private final ThermalBrightnessThrottlingData mData;
+
+ private TestThermalData() {
+ this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, null);
+ }
+
+ private TestThermalData(List<ThrottlingLevel> data) {
+ this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, data);
+ }
+ private TestThermalData(String uniqueDisplayId, String dataId, List<ThrottlingLevel> data) {
+ mUniqueDisplayId = uniqueDisplayId;
+ mDataId = dataId;
+ mData = ThermalBrightnessThrottlingData.create(data);
+ }
+ @NonNull
+ @Override
+ public String getUniqueDisplayId() {
+ return mUniqueDisplayId;
+ }
+
+ @NonNull
+ @Override
+ public String getThermalThrottlingDataId() {
+ return mDataId;
+ }
+
+ @Nullable
+ @Override
+ public ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData() {
+ return mData;
+ }
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/utils/DeviceConfigParsingUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/utils/DeviceConfigParsingUtilsTest.java
new file mode 100644
index 0000000..5e28e63
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/utils/DeviceConfigParsingUtilsTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.os.PowerManager;
+import android.util.Pair;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.annotations.Keep;
+import com.android.server.display.DisplayDeviceConfig;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+@SmallTest
+@RunWith(JUnitParamsRunner.class)
+public class DeviceConfigParsingUtilsTest {
+ private static final String VALID_DATA_STRING = "display1,1,key1,value1";
+ private static final float FLOAT_TOLERANCE = 0.001f;
+
+ private final BiFunction<String, String, Pair<String, String>> mDataPointToPair = Pair::create;
+ private final Function<List<Pair<String, String>>, List<Pair<String, String>>>
+ mDataSetIdentity = (dataSet) -> dataSet;
+
+ @Keep
+ private static Object[][] parseDeviceConfigMapData() {
+ // dataString, expectedMap
+ return new Object[][]{
+ // null
+ {null, Map.of()},
+ // empty string
+ {"", Map.of()},
+ // 1 display, 1 incomplete data point
+ {"display1,1,key1", Map.of()},
+ // 1 display,2 data points required, only 1 present
+ {"display1,2,key1,value1", Map.of()},
+ // 1 display, 1 data point, dataSetId and some extra data
+ {"display1,1,key1,value1,setId1,extraData", Map.of()},
+ // 1 display, random string instead of number of data points
+ {"display1,one,key1,value1", Map.of()},
+ // 1 display, 1 data point no dataSetId
+ {VALID_DATA_STRING, Map.of("display1", Map.of(DisplayDeviceConfig.DEFAULT_ID,
+ List.of(Pair.create("key1", "value1"))))},
+ // 1 display, 1 data point, dataSetId
+ {"display1,1,key1,value1,setId1", Map.of("display1", Map.of("setId1",
+ List.of(Pair.create("key1", "value1"))))},
+ // 1 display, 2 data point, dataSetId
+ {"display1,2,key1,value1,key2,value2,setId1", Map.of("display1", Map.of("setId1",
+ List.of(Pair.create("key1", "value1"), Pair.create("key2", "value2"))))},
+ };
+ }
+
+ @Test
+ @Parameters(method = "parseDeviceConfigMapData")
+ public void testParseDeviceConfigMap(String dataString,
+ Map<String, Map<String, List<Pair<String, String>>>> expectedMap) {
+ Map<String, Map<String, List<Pair<String, String>>>> result =
+ DeviceConfigParsingUtils.parseDeviceConfigMap(dataString, mDataPointToPair,
+ mDataSetIdentity);
+
+ assertEquals(expectedMap, result);
+ }
+
+ @Test
+ public void testDataPointMapperReturnsNull() {
+ Map<String, Map<String, List<Pair<String, String>>>> result =
+ DeviceConfigParsingUtils.parseDeviceConfigMap(VALID_DATA_STRING, (s1, s2) -> null,
+ mDataSetIdentity);
+
+ assertEquals(Map.of(), result);
+ }
+
+ @Test
+ public void testDataSetMapperReturnsNull() {
+ Map<String, Map<String, List<Pair<String, String>>>> result =
+ DeviceConfigParsingUtils.parseDeviceConfigMap(VALID_DATA_STRING, mDataPointToPair,
+ (dataSet) -> null);
+
+ assertEquals(Map.of(), result);
+ }
+
+ @Keep
+ private static Object[][] parseThermalStatusData() {
+ // thermalStatusString, expectedThermalStatus
+ return new Object[][]{
+ {"none", PowerManager.THERMAL_STATUS_NONE},
+ {"light", PowerManager.THERMAL_STATUS_LIGHT},
+ {"moderate", PowerManager.THERMAL_STATUS_MODERATE},
+ {"severe", PowerManager.THERMAL_STATUS_SEVERE},
+ {"critical", PowerManager.THERMAL_STATUS_CRITICAL},
+ {"emergency", PowerManager.THERMAL_STATUS_EMERGENCY},
+ {"shutdown", PowerManager.THERMAL_STATUS_SHUTDOWN},
+ };
+ }
+
+ @Test
+ @Parameters(method = "parseThermalStatusData")
+ public void testParseThermalStatus(String thermalStatusString,
+ @PowerManager.ThermalStatus int expectedThermalStatus) {
+ int result = DeviceConfigParsingUtils.parseThermalStatus(thermalStatusString);
+
+ assertEquals(expectedThermalStatus, result);
+ }
+
+ @Test
+ public void testParseThermalStatus_illegalStatus() {
+ Throwable result = assertThrows(IllegalArgumentException.class,
+ () -> DeviceConfigParsingUtils.parseThermalStatus("invalid_status"));
+
+ assertEquals("Invalid Thermal Status: invalid_status", result.getMessage());
+ }
+
+ @Test
+ public void testParseBrightness() {
+ float result = DeviceConfigParsingUtils.parseBrightness("0.65");
+
+ assertEquals(0.65, result, FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testParseBrightness_lessThanMin() {
+ Throwable result = assertThrows(IllegalArgumentException.class,
+ () -> DeviceConfigParsingUtils.parseBrightness("-0.65"));
+
+ assertEquals("Brightness value out of bounds: -0.65", result.getMessage());
+ }
+
+ @Test
+ public void testParseBrightness_moreThanMax() {
+ Throwable result = assertThrows(IllegalArgumentException.class,
+ () -> DeviceConfigParsingUtils.parseBrightness("1.65"));
+
+ assertEquals("Brightness value out of bounds: 1.65", result.getMessage());
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/SensorUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/utils/SensorUtilsTest.java
similarity index 100%
rename from services/tests/displayservicetests/src/com/android/server/display/SensorUtilsTest.java
rename to services/tests/displayservicetests/src/com/android/server/display/utils/SensorUtilsTest.java
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 6bcc14e..a147098 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/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 212a243..cd3a78e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -52,6 +52,7 @@
import android.app.GameModeInfo;
import android.app.GameState;
import android.app.IGameModeListener;
+import android.app.IGameStateListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -1578,6 +1579,71 @@
assertFalse(gameManagerService.mHandler.hasMessages(SET_GAME_STATE));
}
+ @Test
+ public void testAddGameStateListener() throws Exception {
+ mockModifyGameModeGranted();
+ GameManagerService gameManagerService =
+ new GameManagerService(mMockContext, mTestLooper.getLooper());
+ mockDeviceConfigAll();
+ startUser(gameManagerService, USER_ID_1);
+
+ IGameStateListener mockListener = Mockito.mock(IGameStateListener.class);
+ IBinder binder = Mockito.mock(IBinder.class);
+ when(mockListener.asBinder()).thenReturn(binder);
+ gameManagerService.addGameStateListener(mockListener);
+ verify(binder).linkToDeath(mDeathRecipientCaptor.capture(), anyInt());
+
+ mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_AUDIO);
+ GameState gameState = new GameState(true, GameState.MODE_NONE);
+ gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+ assertFalse(gameManagerService.mHandler.hasMessages(SET_GAME_STATE));
+ mTestLooper.dispatchAll();
+ verify(mockListener, never()).onGameStateChanged(anyString(), any(), anyInt());
+
+ mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_GAME);
+ gameState = new GameState(true, GameState.MODE_NONE);
+ gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+ assertTrue(gameManagerService.mHandler.hasMessages(SET_GAME_STATE));
+ mTestLooper.dispatchAll();
+ verify(mockListener).onGameStateChanged(mPackageName, gameState, USER_ID_1);
+ reset(mockListener);
+
+ gameState = new GameState(false, GameState.MODE_CONTENT);
+ gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+ mTestLooper.dispatchAll();
+ verify(mockListener).onGameStateChanged(mPackageName, gameState, USER_ID_1);
+ reset(mockListener);
+
+ mDeathRecipientCaptor.getValue().binderDied();
+ verify(binder).unlinkToDeath(eq(mDeathRecipientCaptor.getValue()), anyInt());
+ gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+ assertTrue(gameManagerService.mHandler.hasMessages(SET_GAME_STATE));
+ mTestLooper.dispatchAll();
+ verify(mockListener, never()).onGameStateChanged(anyString(), any(), anyInt());
+ }
+
+ @Test
+ public void testRemoveGameStateListener() throws Exception {
+ mockModifyGameModeGranted();
+ GameManagerService gameManagerService =
+ new GameManagerService(mMockContext, mTestLooper.getLooper());
+ mockDeviceConfigAll();
+ startUser(gameManagerService, USER_ID_1);
+
+ IGameStateListener mockListener = Mockito.mock(IGameStateListener.class);
+ IBinder binder = Mockito.mock(IBinder.class);
+ when(mockListener.asBinder()).thenReturn(binder);
+
+ gameManagerService.addGameStateListener(mockListener);
+ gameManagerService.removeGameStateListener(mockListener);
+ mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_GAME);
+ GameState gameState = new GameState(false, GameState.MODE_CONTENT);
+ gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+ assertTrue(gameManagerService.mHandler.hasMessages(SET_GAME_STATE));
+ mTestLooper.dispatchAll();
+ verify(mockListener, never()).onGameStateChanged(anyString(), any(), anyInt());
+ }
+
private List<String> readGameModeInterventionList() throws Exception {
final File interventionFile = new File(InstrumentationRegistry.getContext().getFilesDir(),
"system/game_mode_intervention.list");
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java
index 50996d7..95c62ae 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayBrightnessStateTest.java
@@ -43,25 +43,50 @@
public void validateAllDisplayBrightnessStateFieldsAreSetAsExpected() {
float brightness = 0.3f;
float sdrBrightness = 0.2f;
+ boolean shouldUseAutoBrightness = true;
BrightnessReason brightnessReason = new BrightnessReason();
brightnessReason.setReason(BrightnessReason.REASON_AUTOMATIC);
brightnessReason.setModifier(BrightnessReason.MODIFIER_DIMMED);
- DisplayBrightnessState displayBrightnessState =
- mDisplayBrightnessStateBuilder.setBrightness(brightness).setSdrBrightness(
- sdrBrightness).setBrightnessReason(brightnessReason).build();
+ DisplayBrightnessState displayBrightnessState = mDisplayBrightnessStateBuilder
+ .setBrightness(brightness)
+ .setSdrBrightness(sdrBrightness)
+ .setBrightnessReason(brightnessReason)
+ .setShouldUseAutoBrightness(shouldUseAutoBrightness)
+ .build();
assertEquals(displayBrightnessState.getBrightness(), brightness, FLOAT_DELTA);
assertEquals(displayBrightnessState.getSdrBrightness(), sdrBrightness, FLOAT_DELTA);
assertEquals(displayBrightnessState.getBrightnessReason(), brightnessReason);
+ assertEquals(displayBrightnessState.getShouldUseAutoBrightness(), shouldUseAutoBrightness);
assertEquals(displayBrightnessState.toString(), getString(displayBrightnessState));
}
+ @Test
+ public void testFrom() {
+ BrightnessReason reason = new BrightnessReason();
+ reason.setReason(BrightnessReason.REASON_MANUAL);
+ reason.setModifier(BrightnessReason.MODIFIER_DIMMED);
+ DisplayBrightnessState state1 = new DisplayBrightnessState.Builder()
+ .setBrightnessReason(reason)
+ .setBrightness(0.26f)
+ .setSdrBrightness(0.23f)
+ .setShouldUseAutoBrightness(false)
+ .build();
+ DisplayBrightnessState state2 = DisplayBrightnessState.Builder.from(state1).build();
+ assertEquals(state1, state2);
+ }
+
private String getString(DisplayBrightnessState displayBrightnessState) {
StringBuilder sb = new StringBuilder();
- sb.append("DisplayBrightnessState:");
- sb.append("\n brightness:" + displayBrightnessState.getBrightness());
- sb.append("\n sdrBrightness:" + displayBrightnessState.getSdrBrightness());
- sb.append("\n brightnessReason:" + displayBrightnessState.getBrightnessReason());
+ sb.append("DisplayBrightnessState:")
+ .append("\n brightness:")
+ .append(displayBrightnessState.getBrightness())
+ .append("\n sdrBrightness:")
+ .append(displayBrightnessState.getSdrBrightness())
+ .append("\n brightnessReason:")
+ .append(displayBrightnessState.getBrightnessReason())
+ .append("\n shouldUseAutoBrightness:")
+ .append(displayBrightnessState.getShouldUseAutoBrightness());
return sb.toString();
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index aaab403..c710d1c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -714,6 +714,8 @@
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF);
+
DisplayPowerRequest dpr = new DisplayPowerRequest();
dpr.policy = DisplayPowerRequest.POLICY_OFF;
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
@@ -751,6 +753,7 @@
Settings.System.SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+ when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
DisplayPowerRequest dpr = new DisplayPowerRequest();
dpr.policy = DisplayPowerRequest.POLICY_DOZE;
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
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/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 8346050..0cfddd3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -106,7 +106,7 @@
@Mock private KeyStore mKeyStore;
@Mock private AuthSession.ClientDeathReceiver mClientDeathReceiver;
@Mock private BiometricFrameworkStatsLogger mBiometricFrameworkStatsLogger;
- @Mock BiometricSensorPrivacy mBiometricSensorPrivacy;
+ @Mock private BiometricCameraManager mBiometricCameraManager;
private Random mRandom;
private IBinder mToken;
@@ -609,7 +609,7 @@
TEST_PACKAGE,
checkDevicePolicyManager,
mContext,
- mBiometricSensorPrivacy);
+ mBiometricCameraManager);
}
private AuthSession createAuthSession(List<BiometricSensor> sensors,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 41f7dbc..6821721 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -151,6 +151,8 @@
private AuthSessionCoordinator mAuthSessionCoordinator;
@Mock
private UserManager mUserManager;
+ @Mock
+ private BiometricCameraManager mBiometricCameraManager;
BiometricContextProvider mBiometricContextProvider;
@@ -177,6 +179,7 @@
when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager);
when(mInjector.getRequestGenerator()).thenReturn(() -> TEST_REQUEST_ID);
when(mInjector.getUserManager(any())).thenReturn(mUserManager);
+ when(mInjector.getBiometricCameraManager(any())).thenReturn(mBiometricCameraManager);
when(mResources.getString(R.string.biometric_error_hw_unavailable))
.thenReturn(ERROR_HW_UNAVAILABLE);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
index 0c98c8d..c2bdf50 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java
@@ -67,7 +67,7 @@
@Mock
BiometricService.SettingObserver mSettingObserver;
@Mock
- BiometricSensorPrivacy mBiometricSensorPrivacyUtil;
+ BiometricCameraManager mBiometricCameraManager;
@Before
public void setup() throws RemoteException {
@@ -79,11 +79,13 @@
when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
when(mFaceAuthenticator.getLockoutModeForUser(anyInt()))
.thenReturn(LOCKOUT_NONE);
+ when(mBiometricCameraManager.isCameraPrivacyEnabled()).thenReturn(false);
+ when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(false);
}
@Test
public void testFaceAuthentication_whenCameraPrivacyIsEnabled() throws Exception {
- when(mBiometricSensorPrivacyUtil.isCameraPrivacyEnabled()).thenReturn(true);
+ when(mBiometricCameraManager.isCameraPrivacyEnabled()).thenReturn(true);
BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE,
BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) {
@@ -104,15 +106,14 @@
PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
mSettingObserver, List.of(sensor),
0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
- false /* checkDevicePolicyManager */, mContext, mBiometricSensorPrivacyUtil);
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager);
assertThat(preAuthInfo.eligibleSensors).isEmpty();
}
@Test
- public void testFaceAuthentication_whenCameraPrivacyIsDisabled() throws Exception {
- when(mBiometricSensorPrivacyUtil.isCameraPrivacyEnabled()).thenReturn(false);
-
+ public void testFaceAuthentication_whenCameraPrivacyIsDisabledAndCameraIsAvailable()
+ throws Exception {
BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE,
BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) {
@Override
@@ -132,8 +133,35 @@
PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
mSettingObserver, List.of(sensor),
0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
- false /* checkDevicePolicyManager */, mContext, mBiometricSensorPrivacyUtil);
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager);
assertThat(preAuthInfo.eligibleSensors).hasSize(1);
}
+
+ @Test
+ public void testFaceAuthentication_whenCameraIsUnavailable() throws RemoteException {
+ when(mBiometricCameraManager.isAnyCameraUnavailable()).thenReturn(true);
+ BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE,
+ BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) {
+ @Override
+ boolean confirmationAlwaysRequired(int userId) {
+ return false;
+ }
+
+ @Override
+ boolean confirmationSupported() {
+ return false;
+ }
+ };
+ PromptInfo promptInfo = new PromptInfo();
+ promptInfo.setConfirmationRequested(false /* requireConfirmation */);
+ promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
+ promptInfo.setDisallowBiometricsIfPolicyExists(false /* checkDevicePolicy */);
+ PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
+ mSettingObserver, List.of(sensor),
+ 0 /* userId */, promptInfo, TEST_PACKAGE_NAME,
+ false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager);
+
+ assertThat(preAuthInfo.eligibleSensors).hasSize(0);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index 0b13f9a..5f84e9e 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -30,6 +30,7 @@
import android.provider.Settings.Global;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.util.ArrayMap;
import com.android.frameworks.servicestests.R;
@@ -115,6 +116,7 @@
testServiceDefaultValue_On(ServiceType.NULL);
}
+ @Suppress
@SmallTest
public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() {
testServiceDefaultValue_Off(ServiceType.VIBRATION);
@@ -200,6 +202,7 @@
testServiceDefaultValue_On(ServiceType.QUICK_DOZE);
}
+ @Suppress
@SmallTest
public void testUpdateConstants_getCorrectData() {
mBatterySaverPolicy.updateConstantsLocked(BATTERY_SAVER_CONSTANTS, "");
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 30180e8..3c882dc8 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -405,6 +405,7 @@
UriGrantsManagerInternal mUgmInternal;
@Mock
AppOpsManager mAppOpsManager;
+ private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener;
@Mock
private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
mNotificationAssistantAccessGrantedCallback;
@@ -604,6 +605,12 @@
tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName,
SEARCH_SELECTOR_PKG);
+ doAnswer(invocation -> {
+ mOnPermissionChangeListener = invocation.getArgument(2);
+ return null;
+ }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(),
+ any());
+
mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
@@ -2295,8 +2302,8 @@
mTestNotificationChannel, 1, "group", true);
notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
mService.addNotification(notif);
- mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, true,
- notif.getUserId(), 0, null);
+ mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0,
+ notif.getUserId(), 0);
waitForIdle();
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
@@ -3034,7 +3041,7 @@
notif.getNotification().flags |= Notification.FLAG_NO_CLEAR;
mService.addNotification(notif);
mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0,
- Notification.FLAG_ONGOING_EVENT, true, notif.getUserId(), 0, null);
+ Notification.FLAG_ONGOING_EVENT, notif.getUserId(), 0);
waitForIdle();
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
@@ -3061,8 +3068,8 @@
mTestNotificationChannel, 1, "group", true);
notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT;
mService.addNotification(notif);
- mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0, true,
- notif.getUserId(), 0, null);
+ mService.cancelAllNotificationsInt(mUid, 0, PKG, null, 0, 0,
+ notif.getUserId(), 0);
waitForIdle();
StatusBarNotification[] notifs =
mBinderService.getActiveNotifications(notif.getSbn().getPackageName());
@@ -3216,48 +3223,6 @@
}
@Test
- public void testUpdateAppNotifyCreatorBlock() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
-
- mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
- Thread.sleep(500);
- waitForIdle();
-
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
-
- assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
- captor.getValue().getAction());
- assertEquals(PKG, captor.getValue().getPackage());
- assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
- }
-
- @Test
- public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
-
- mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
- verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
- }
-
- @Test
- public void testUpdateAppNotifyCreatorUnblock() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
-
- mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
- Thread.sleep(500);
- waitForIdle();
-
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
-
- assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
- captor.getValue().getAction());
- assertEquals(PKG, captor.getValue().getPackage());
- assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
- }
-
- @Test
public void testUpdateChannelNotifyCreatorBlock() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
@@ -11269,7 +11234,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")
@@ -12174,6 +12138,134 @@
any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER));
}
+ @Test
+ public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()
+ throws RemoteException {
+ // Have preexisting posted notifications from revoked package and other packages.
+ mService.addNotification(new NotificationRecord(mContext,
+ generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel));
+ mService.addNotification(new NotificationRecord(mContext,
+ generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
+ // Have preexisting enqueued notifications from revoked package and other packages.
+ mService.addEnqueuedNotification(new NotificationRecord(mContext,
+ generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel));
+ mService.addEnqueuedNotification(new NotificationRecord(mContext,
+ generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
+ assertThat(mService.mNotificationList).hasSize(2);
+ assertThat(mService.mEnqueuedNotifications).hasSize(2);
+
+ when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001);
+ when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false);
+
+ mOnPermissionChangeListener.onOpChanged(
+ AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0);
+ waitForIdle();
+
+ assertThat(mService.mNotificationList).hasSize(1);
+ assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other");
+ assertThat(mService.mEnqueuedNotifications).hasSize(1);
+ assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo(
+ "other");
+ }
+
+ @Test
+ public void onOpChanged_permissionStillGranted_notificationsAreNotAffected()
+ throws RemoteException {
+ // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission
+ // being now granted, AND having previously posted notifications from said package) should
+ // never happen (if we trust the broadcasts are correct). So this test is for a what-if
+ // scenario, to verify we still handle it reasonably.
+
+ // Have preexisting posted notifications from specific package and other packages.
+ mService.addNotification(new NotificationRecord(mContext,
+ generateSbn("granted", 1001, 1, 0), mTestNotificationChannel));
+ mService.addNotification(new NotificationRecord(mContext,
+ generateSbn("other", 1002, 2, 0), mTestNotificationChannel));
+ // Have preexisting enqueued notifications from specific package and other packages.
+ mService.addEnqueuedNotification(new NotificationRecord(mContext,
+ generateSbn("granted", 1001, 3, 0), mTestNotificationChannel));
+ mService.addEnqueuedNotification(new NotificationRecord(mContext,
+ generateSbn("other", 1002, 4, 0), mTestNotificationChannel));
+ assertThat(mService.mNotificationList).hasSize(2);
+ assertThat(mService.mEnqueuedNotifications).hasSize(2);
+
+ when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001);
+ when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true);
+
+ mOnPermissionChangeListener.onOpChanged(
+ AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0);
+ waitForIdle();
+
+ assertThat(mService.mNotificationList).hasSize(2);
+ assertThat(mService.mEnqueuedNotifications).hasSize(2);
+ }
+
+ @Test
+ public void onOpChanged_permissionGranted_notifiesAppUnblocked() throws Exception {
+ when(mPackageManagerInternal.getPackageUid(PKG, 0, 0)).thenReturn(1001);
+ when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true);
+
+ mOnPermissionChangeListener.onOpChanged(
+ AppOpsManager.OPSTR_POST_NOTIFICATION, PKG, 0);
+ waitForIdle();
+ Thread.sleep(600);
+ waitForIdle();
+
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+ assertThat(captor.getValue().getAction()).isEqualTo(
+ NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED);
+ assertThat(captor.getValue().getPackage()).isEqualTo(PKG);
+ assertThat(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)).isFalse();
+ }
+
+ @Test
+ public void onOpChanged_permissionRevoked_notifiesAppBlocked() throws Exception {
+ when(mPackageManagerInternal.getPackageUid(PKG, 0, 0)).thenReturn(1001);
+ when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false);
+
+ mOnPermissionChangeListener.onOpChanged(
+ AppOpsManager.OPSTR_POST_NOTIFICATION, PKG, 0);
+ waitForIdle();
+ Thread.sleep(600);
+ waitForIdle();
+
+ ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).sendBroadcastAsUser(captor.capture(), any(), eq(null));
+ assertThat(captor.getValue().getAction()).isEqualTo(
+ NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED);
+ assertThat(captor.getValue().getPackage()).isEqualTo(PKG);
+ assertThat(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)).isTrue();
+ }
+
+ @Test
+ public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception {
+ mService.addNotification(new NotificationRecord(mContext,
+ generateSbn("package", 1001, 1, 0), mTestNotificationChannel));
+ assertThat(mService.mNotificationList).hasSize(1);
+ when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001);
+ when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn(
+ true);
+
+ // Start with granted permission and simulate effect of revoking it.
+ when(mPermissionHelper.hasPermission(1001)).thenReturn(true);
+ doAnswer(invocation -> {
+ when(mPermissionHelper.hasPermission(1001)).thenReturn(false);
+ mOnPermissionChangeListener.onOpChanged(
+ AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0);
+ return null;
+ }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true);
+
+ mBinderService.setNotificationsEnabledForPackage("package", 1001, false);
+ waitForIdle();
+
+ assertThat(mService.mNotificationList).hasSize(0);
+
+ Thread.sleep(600);
+ waitForIdle();
+ verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null));
+ }
+
private static <T extends Parcelable> T parcelAndUnparcel(T source,
Parcelable.Creator<T> creator) {
Parcel parcel = Parcel.obtain();
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/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..1ba8f7d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -74,7 +74,6 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -103,6 +102,7 @@
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.service.voice.IVoiceInteractionSession;
@@ -159,6 +159,9 @@
private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
private static final int UNIMPORTANT_UID = 12345;
private static final int UNIMPORTANT_UID2 = 12346;
+ private static final int SDK_SANDBOX_UID = Process.toSdkSandboxUid(UNIMPORTANT_UID);
+ private static final int SECONDARY_USER_SDK_SANDBOX_UID =
+ UserHandle.getUid(10, SDK_SANDBOX_UID);
private static final int CURRENT_IME_UID = 12347;
protected final DeviceConfigStateHelper mDeviceConfig = new DeviceConfigStateHelper(
@@ -958,6 +961,48 @@
mockingSession.finishMocking();
}
+
+ @Test
+ public void testBackgroundActivityStartsAllowed_sdkSandboxClientAppHasVisibleWindow() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ // The SDK's associated client app has a visible window
+ doReturn(true).when(mAtm).hasActiveVisibleWindow(
+ Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "allowed_sdkSandboxClientAppHasVisibleWindow", false, SDK_SANDBOX_UID,
+ false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false,
+ PROCESS_STATE_TOP, true, false, false,
+ false, false, false, false, false);
+ }
+
+ @Test
+ public void testBackgroundActivityStartsDisallowed_sdkSandboxClientHasNoVisibleWindow() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ // The SDK's associated client app does not have a visible window
+ doReturn(false).when(mAtm).hasActiveVisibleWindow(
+ Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "disallowed_sdkSandboxClientHasNoVisibleWindow", true, SDK_SANDBOX_UID,
+ false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false,
+ PROCESS_STATE_TOP, true, false, false,
+ false, false, false, false, false);
+
+ }
+
+ @Test
+ public void testBackgroundActivityStartsAllowed_sdkSandboxMultiUserClientHasVisibleWindow() {
+ doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
+ // The SDK's associated client app has a visible window
+ doReturn(true).when(mAtm).hasActiveVisibleWindow(
+ Process.getAppUidForSdkSandboxUid(SECONDARY_USER_SDK_SANDBOX_UID));
+ runAndVerifyBackgroundActivityStartsSubtest(
+ "allowed_sdkSandboxMultiUserClientHasVisibleWindow", false,
+ SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP,
+ SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP,
+ false, false, false, false,
+ false, false, false, false);
+ }
+
private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 99ab715..54b9351 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -26,6 +26,7 @@
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.window.TaskFragmentOperation.OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_DELETE_TASK_FRAGMENT;
+import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
import static android.window.TaskFragmentOperation.OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
@@ -1590,6 +1591,46 @@
assertEquals(taskFragmentBounds, mTaskFragment.getBounds());
}
+ @Test
+ public void testApplyTransaction_reorderTaskFragmentToFront() {
+ final Task task = createTask(mDisplayContent);
+ // Create a TaskFragment.
+ final IBinder token0 = new Binder();
+ final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(token0)
+ .setOrganizer(mOrganizer)
+ .createActivityCount(1)
+ .build();
+ // Create another TaskFragment
+ final IBinder token1 = new Binder();
+ final TaskFragment tf1 = new TaskFragmentBuilder(mAtm)
+ .setParentTask(task)
+ .setFragmentToken(token1)
+ .setOrganizer(mOrganizer)
+ .createActivityCount(1)
+ .build();
+ // Create a non-embedded Activity on top.
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm)
+ .setTask(task)
+ .build();
+ mWindowOrganizerController.mLaunchTaskFragments.put(token0, tf0);
+ mWindowOrganizerController.mLaunchTaskFragments.put(token1, tf1);
+
+ // Reorder TaskFragment to front
+ final TaskFragmentOperation operation = new TaskFragmentOperation.Builder(
+ OP_TYPE_REORDER_TO_FRONT).build();
+ mTransaction.addTaskFragmentOperation(token0, operation);
+ assertApplyTransactionAllowed(mTransaction);
+
+ // Ensure the non-embedded activity still on top.
+ assertEquals(topActivity, task.getTopChild().asActivityRecord());
+
+ // Ensure the TaskFragment is moved to front.
+ final TaskFragment frontMostTaskFragment = task.getTaskFragment(tf -> tf.asTask() == null);
+ assertEquals(frontMostTaskFragment, tf0);
+ }
+
/**
* Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
* {@link WindowOrganizerController#applyTransaction(WindowContainerTransaction)} to apply the
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 64330d8..b77e4cf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -1028,7 +1028,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 b0552b4..182d2fc 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,27 @@
}
/**
+ * 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}.
+ * @hide
+ */
+ public boolean isNonTerrestrialNetwork() {
+ return mIsNonTerrestrialNetwork;
+ }
+
+ /**
* @hide
*/
@Nullable
@@ -769,6 +798,7 @@
? nrStateToString(mNrState) : "****")
.append(" rRplmn=").append(mRplmn)
.append(" isUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
+ .append(" isNonTerrestrialNetwork=").append(mIsNonTerrestrialNetwork)
.append("}").toString();
}
@@ -777,7 +807,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 +833,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 +858,7 @@
dest.writeInt(mNrState);
dest.writeString(mRplmn);
dest.writeBoolean(mIsUsingCarrierAggregation);
+ dest.writeBoolean(mIsNonTerrestrialNetwork);
}
/**
@@ -936,6 +968,8 @@
@Nullable
private VoiceSpecificRegistrationInfo mVoiceSpecificRegistrationInfo;
+ private boolean mIsNonTerrestrialNetwork;
+
/**
* Default constructor for Builder.
*/
@@ -964,6 +998,7 @@
mVoiceSpecificRegistrationInfo = new VoiceSpecificRegistrationInfo(
nri.mVoiceSpecificInfo);
}
+ mIsNonTerrestrialNetwork = nri.mIsNonTerrestrialNetwork;
}
/**
@@ -1111,6 +1146,19 @@
}
/**
+ * 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.
+ * @hide
+ */
+ public @NonNull Builder setIsNonTerrestrialNetwork(boolean isNonTerrestrialNetwork) {
+ mIsNonTerrestrialNetwork = isNonTerrestrialNetwork;
+ return this;
+ }
+
+ /**
* Build the NetworkRegistrationInfo.
* @return the NetworkRegistrationInfo object.
* @hide
@@ -1120,7 +1168,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..74cfbea 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -2250,4 +2250,19 @@
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}.
+ * @hide
+ */
+ public boolean isUsingNonTerrestrialNetwork() {
+ synchronized (mNetworkRegistrationInfos) {
+ for (NetworkRegistrationInfo nri : mNetworkRegistrationInfos) {
+ if (nri.isNonTerrestrialNetwork()) return true;
+ }
+ }
+ return false;
+ }
}
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..c05dc32
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.datatypes.Region
+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()
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index ced7a1e..eac8813 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/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/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;
}
}