Merge "Move #mDeviceIdToShowIme to binding controller" into main
diff --git a/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt b/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
index 2af878e..daf991c 100644
--- a/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
+++ b/apct-tests/perftests/core/src/android/permission/AppOpsPerfTest.kt
@@ -17,8 +17,7 @@
import android.app.AppOpsManager
import android.content.Context
-import androidx.benchmark.BenchmarkState
-import androidx.benchmark.junit4.BenchmarkRule
+import android.perftests.utils.PerfStatusReporter
import androidx.test.core.app.ApplicationProvider
import androidx.test.filters.LargeTest
import org.junit.Before
@@ -34,7 +33,7 @@
* these APIs should be monitored closely for performance.
*/
class AppOpsPerfTest {
- @get:Rule val mBenchmarkRule: BenchmarkRule = BenchmarkRule()
+ @get:Rule val perfStatusReporter = PerfStatusReporter()
private lateinit var appOpsManager: AppOpsManager
private lateinit var opPackageName: String
private var opPackageUid: Int = 0
@@ -49,7 +48,7 @@
@Test
fun testNoteOp() {
- val state: BenchmarkState = mBenchmarkRule.getState()
+ val state = perfStatusReporter.benchmarkState
while (state.keepRunning()) {
appOpsManager.noteOp(
AppOpsManager.OPSTR_FINE_LOCATION,
@@ -63,7 +62,7 @@
@Test
fun testUnsafeCheckOp() {
- val state: BenchmarkState = mBenchmarkRule.getState()
+ val state = perfStatusReporter.benchmarkState
while (state.keepRunning()) {
appOpsManager.unsafeCheckOp(
AppOpsManager.OPSTR_FINE_LOCATION,
diff --git a/core/api/current.txt b/core/api/current.txt
index bbb3932..9d506b4 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19910,7 +19910,6 @@
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public final class ExtensionCaptureRequest {
- ctor public ExtensionCaptureRequest();
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> EFV_AUTO_ZOOM;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> EFV_MAX_PADDING_ZOOM_FACTOR;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> EFV_PADDING_ZOOM_FACTOR;
@@ -19923,7 +19922,6 @@
}
@FlaggedApi("com.android.internal.camera.flags.concert_mode_api") public final class ExtensionCaptureResult {
- ctor public ExtensionCaptureResult();
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> EFV_AUTO_ZOOM;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<int[]> EFV_AUTO_ZOOM_PADDING_REGION;
field @FlaggedApi("com.android.internal.camera.flags.concert_mode_api") @NonNull public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> EFV_MAX_PADDING_ZOOM_FACTOR;
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index 1b0da05..e6a7ca5 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -245,14 +245,6 @@
Field 'ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE' is missing @BroadcastBehavior
-CompileTimeConstant: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_GIMBAL:
- All constants must be defined at compile time: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_GIMBAL
-CompileTimeConstant: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED:
- All constants must be defined at compile time: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_LOCKED
-CompileTimeConstant: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_OFF:
- All constants must be defined at compile time: android.hardware.camera2.ExtensionCaptureRequest#EFV_STABILIZATION_MODE_OFF
-
-
DeprecationMismatch: android.accounts.AccountManager#newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle):
Method android.accounts.AccountManager.newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, String[], boolean, String, String, String[], android.os.Bundle): @Deprecated annotation (present) and @deprecated doc tag (not present) do not match
DeprecationMismatch: android.app.Activity#enterPictureInPictureMode():
@@ -1095,14 +1087,6 @@
Method 'setGeolocationEnabled' documentation mentions permissions without declaring @RequiresPermission
-StaticUtils: ExtensionCaptureRequest:
- Fully-static utility classes must not have constructor
-StaticUtils: android.hardware.camera2.ExtensionCaptureRequest:
- Fully-static utility classes must not have constructor
-StaticUtils: android.hardware.camera2.ExtensionCaptureResult:
- Fully-static utility classes must not have constructor
-
-
Todo: android.hardware.camera2.params.StreamConfigurationMap:
Documentation mentions 'TODO'
Todo: android.provider.ContactsContract.RawContacts#newEntityIterator(android.database.Cursor):
@@ -1462,14 +1446,6 @@
UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int):
New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int)
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest:
- New API must be flagged with @FlaggedApi: class android.hardware.camera2.ExtensionCaptureRequest
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureRequest#ExtensionCaptureRequest():
- New API must be flagged with @FlaggedApi: constructor android.hardware.camera2.ExtensionCaptureRequest()
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureResult:
- New API must be flagged with @FlaggedApi: class android.hardware.camera2.ExtensionCaptureResult
-UnflaggedApi: android.hardware.camera2.ExtensionCaptureResult#ExtensionCaptureResult():
- New API must be flagged with @FlaggedApi: constructor android.hardware.camera2.ExtensionCaptureResult()
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_CAR:
New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_CAR
UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_COMPUTER:
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 14ae3f5..d03dd16 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -46,6 +46,7 @@
field public static final String REMAP_MODIFIER_KEYS = "android.permission.REMAP_MODIFIER_KEYS";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String REQUEST_UNIQUE_ID_ATTESTATION = "android.permission.REQUEST_UNIQUE_ID_ATTESTATION";
+ field public static final String RESERVED_FOR_TESTING_SIGNATURE = "android.permission.RESERVED_FOR_TESTING_SIGNATURE";
field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS";
field public static final String REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL = "android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL";
field public static final String SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS = "android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS";
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index 6cc71e5..b4a3abc 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -1973,6 +1973,8 @@
UnflaggedApi: android.Manifest.permission#MANAGE_REMOTE_AUTH:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_REMOTE_AUTH
+UnflaggedApi: android.Manifest.permission#RESERVED_FOR_TESTING_SIGNATURE:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.RESERVED_FOR_TESTING_SIGNATURE
UnflaggedApi: android.Manifest.permission#START_ACTIVITIES_FROM_SDK_SANDBOX:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.START_ACTIVITIES_FROM_SDK_SANDBOX
UnflaggedApi: android.Manifest.permission#USE_REMOTE_AUTH:
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 79e2bd4..1c247a6 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -9291,11 +9291,11 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG,
"dispatchMultiWindowModeChanged " + this + ": " + isInMultiWindowMode
+ " " + newConfig);
+ mIsInMultiWindowMode = isInMultiWindowMode;
mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig);
if (mWindow != null) {
mWindow.onMultiWindowModeChanged();
}
- mIsInMultiWindowMode = isInMultiWindowMode;
onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
}
@@ -9304,11 +9304,11 @@
if (DEBUG_LIFECYCLE) Slog.v(TAG,
"dispatchPictureInPictureModeChanged " + this + ": " + isInPictureInPictureMode
+ " " + newConfig);
+ mIsInPictureInPictureMode = isInPictureInPictureMode;
mFragments.dispatchPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
if (mWindow != null) {
mWindow.onPictureInPictureModeChanged(isInPictureInPictureMode);
}
- mIsInPictureInPictureMode = isInPictureInPictureMode;
onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9785252..83c3bf6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -477,6 +477,11 @@
*/
public static final int OOM_ADJ_REASON_COMPONENT_DISABLED = 22;
+ /**
+ * Oom Adj Reason: Follow up update for time sensitive state evaluations.
+ */
+ public static final int OOM_ADJ_REASON_FOLLOW_UP = 23;
+
@IntDef(prefix = {"OOM_ADJ_REASON_"}, value = {
OOM_ADJ_REASON_NONE,
OOM_ADJ_REASON_ACTIVITY,
@@ -501,6 +506,7 @@
OOM_ADJ_REASON_EXECUTING_SERVICE,
OOM_ADJ_REASON_RESTRICTION_CHANGE,
OOM_ADJ_REASON_COMPONENT_DISABLED,
+ OOM_ADJ_REASON_FOLLOW_UP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface OomAdjReason {}
diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java
index e5316bc0..a488689 100644
--- a/core/java/android/app/assist/AssistContent.java
+++ b/core/java/android/app/assist/AssistContent.java
@@ -34,12 +34,22 @@
}
/**
+ * Create an AssistContent with extras initialized.
+ *
* @hide
+ */
+ public AssistContent(@android.annotation.NonNull Bundle extras) {
+ mExtras = extras;
+ }
+
+ /**
* Called by {@link android.app.ActivityThread} to set the default Intent based on
* {@link android.app.Activity#getIntent Activity.getIntent}.
*
* <p>Automatically populates {@link #mUri} if that Intent is an {@link Intent#ACTION_VIEW}
* of a web (http or https scheme) URI.</p>
+ *
+ * @hide
*/
public void setDefaultIntent(Intent intent) {
mIntent = intent;
diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig
index 3385b2b..3b0c867 100644
--- a/core/java/android/app/contextualsearch/flags.aconfig
+++ b/core/java/android/app/contextualsearch/flags.aconfig
@@ -7,3 +7,9 @@
description: "Flag to enable the service"
bug: "309689654"
}
+flag {
+ name: "enable_token_refresh"
+ namespace: "machine_learning"
+ description: "Flag to refresh the token to the callback"
+ bug: "309689654"
+}
\ No newline at end of file
diff --git a/core/java/android/companion/ObservingDevicePresenceRequest.java b/core/java/android/companion/ObservingDevicePresenceRequest.java
index 11ea735..3150b87 100644
--- a/core/java/android/companion/ObservingDevicePresenceRequest.java
+++ b/core/java/android/companion/ObservingDevicePresenceRequest.java
@@ -180,6 +180,9 @@
* <p>Calling apps must use either this API or {@link #setAssociationId(int)},
* but not both.</p>
*
+ * <p>Calling app must hold the
+ * {@link AssociationRequest#DEVICE_PROFILE_AUTOMOTIVE_PROJECTION} profile.</p>
+ *
* @param uuid The ParcelUuid for observing device presence.
*/
@NonNull
diff --git a/core/java/android/hardware/camera2/ExtensionCaptureRequest.java b/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
index c33956b..b681ce4 100644
--- a/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
+++ b/core/java/android/hardware/camera2/ExtensionCaptureRequest.java
@@ -18,7 +18,6 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureRequest.Key;
import android.hardware.camera2.impl.ExtensionKey;
@@ -43,6 +42,9 @@
@FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
public final class ExtensionCaptureRequest {
+ /** To avoid exposing constructor */
+ private ExtensionCaptureRequest() {}
+
/**
* <p>Used to apply an additional digital zoom factor for the
* {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
diff --git a/core/java/android/hardware/camera2/ExtensionCaptureResult.java b/core/java/android/hardware/camera2/ExtensionCaptureResult.java
index 95feb2f..b7ba78c 100644
--- a/core/java/android/hardware/camera2/ExtensionCaptureResult.java
+++ b/core/java/android/hardware/camera2/ExtensionCaptureResult.java
@@ -18,7 +18,6 @@
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraExtensionCharacteristics;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.CaptureResult.Key;
@@ -45,6 +44,9 @@
@FlaggedApi(Flags.FLAG_CONCERT_MODE_API)
public final class ExtensionCaptureResult {
+ /** To avoid exposing constructor */
+ private ExtensionCaptureResult() {}
+
/**
* <p>The padding region for the
* {@link android.hardware.camera2.CameraExtensionCharacteristics#EXTENSION_EYES_FREE_VIDEOGRAPHY }
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
index 8898a4c..df057a1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceSetupImpl.java
@@ -105,7 +105,8 @@
try {
return cameraService.isSessionConfigurationWithParametersSupported(mCameraId,
- mTargetSdkVersion, config, mContext.getDeviceId(),
+ mTargetSdkVersion, config,
+ mContext.getDeviceId(),
mCameraManager.getDevicePolicyFromContext(mContext));
} catch (ServiceSpecificException e) {
throw ExceptionUtils.throwAsPublicException(e);
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index dda52dd..ebcc371 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -638,13 +638,15 @@
/**
* Create a list of {@link OutputConfiguration} instances for a
- * {@link android.hardware.camera2.params.MultiResolutionImageReader}.
+ * {@link MultiResolutionImageReader}.
*
* <p>This method can be used to create query OutputConfigurations for a
* MultiResolutionImageReader that can be included in a SessionConfiguration passed into
- * {@link CameraDeviceSetup#isSessionConfigurationSupported} before opening and setting up
- * a camera device in full, at which point {@link #setSurfacesForMultiResolutionOutput}
- * can be used to link to the actual MultiResolutionImageReader.</p>
+ * {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * before opening and setting up a camera device in full, at which point {@link
+ * #setSurfacesForMultiResolutionOutput} can be used to link to the actual
+ * MultiResolutionImageReader.</p>
*
* <p>This constructor takes same arguments used to create a {@link
* MultiResolutionImageReader}: a collection of {@link MultiResolutionStreamInfo}
@@ -655,12 +657,12 @@
* @param format The format of the MultiResolutionImageReader. This must be one of the {@link
* android.graphics.ImageFormat} or {@link android.graphics.PixelFormat} constants
* supported by the camera device. Note that not all formats are supported, like
- * {@link ImageFormat.NV21}. The supported multi-resolution reader format can be
+ * {@link ImageFormat#NV21}. The supported multi-resolution reader format can be
* queried by {@link MultiResolutionStreamConfigurationMap#getOutputFormats}.
*
* @return The list of {@link OutputConfiguration} objects for a MultiResolutionImageReader.
*
- * @throws IllegaArgumentException If the {@code streams} is null or doesn't contain
+ * @throws IllegalArgumentException If the {@code streams} is null or doesn't contain
* at least 2 items, or if {@code format} isn't a valid camera
* format.
*
@@ -710,7 +712,7 @@
* instances.</p>
*
* @param outputConfigurations The OutputConfiguration objects created by {@link
- * #createInstancesFromMultiResolutionOutput}
+ * #createInstancesForMultiResolutionOutput}
* @param multiResolutionImageReader The MultiResolutionImageReader object created from the same
* MultiResolutionStreamInfo parameters as
* {@code outputConfigurations}.
@@ -759,31 +761,33 @@
* the deferred Surface can be obtained: (1) from {@link android.view.SurfaceView}
* by calling {@link android.view.SurfaceHolder#getSurface}, (2) from
* {@link android.graphics.SurfaceTexture} via
- * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}, (3) from {@link
- * android.media.MediaRecorder} via {@link android.media.MediaRecorder.getSurface} or {@link
- * android.media.MediaCodec#createPersistentInputSurface}, or (4) from {@link
- * android.media.MediaCodce} via {@link android.media.MediaCodec#createInputSurface} or {@link
- * android.media.MediaCodec#createPersistentInputSource}.</p>
+ * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}, (3) from
+ * {@link android.media.MediaRecorder} via {@link android.media.MediaRecorder#getSurface} or
+ * {@link android.media.MediaCodec#createPersistentInputSurface}, or (4) from
+ * {@link android.media.MediaCodec} via {@link android.media.MediaCodec#createInputSurface} or
+ * {@link android.media.MediaCodec#createPersistentInputSurface}.</p>
*
* <ul>
* <li>Surfaces for {@link android.view.SurfaceView} and {@link android.graphics.SurfaceTexture}
* can be deferred until after {@link CameraDevice#createCaptureSession}. In that case, the
* output Surface must be set via {@link #addSurface}, and the Surface configuration must be
- * finalized via {@link CameraCaptureSession#finalizeOutputConfiguration} before submitting
+ * finalized via {@link CameraCaptureSession#finalizeOutputConfigurations} before submitting
* a request with the Surface target.</li>
* <li>For all other target types, the output Surface must be set by {@link #addSurface},
- * and {@link CameraCaptureSession#finalizeOutputConfiguration} is not needed because the
+ * and {@link CameraCaptureSession#finalizeOutputConfigurations} is not needed because the
* OutputConfiguration used to create the session will contain the actual Surface.</li>
* </ul>
*
* <p>Before {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM Android V}, only {@link
* android.view.SurfaceView} and {@link android.graphics.SurfaceTexture} are supported. Both
* kind of outputs can be deferred until after {@link
- * CameraDevice#createCaptureSessionByOutputConfiguration}.</p>
+ * CameraDevice#createCaptureSessionByOutputConfigurations}.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param surfaceSize Size for the deferred surface.
* @param klass a non-{@code null} {@link Class} object reference that indicates the source of
@@ -849,8 +853,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param format The format of the ImageReader output. This must be one of the
* {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat}
@@ -873,8 +879,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param surfaceGroupId A group ID for this output, used for sharing memory between multiple
* outputs.
@@ -899,8 +907,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param format The format of the ImageReader output. This must be one of the
* {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat}
@@ -923,8 +933,10 @@
* before creating the capture session.</p>
*
* <p>An OutputConfiguration object created by this constructor can be used for {@link
- * CameraDeviceSetup.isSessionConfigurationSupported} and {@link
- * CameraDeviceSetup.getSessionCharacteristics} without having called {@link #addSurface}.</p>
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#isSessionConfigurationSupported}
+ * and {@link
+ * android.hardware.camera2.CameraDevice.CameraDeviceSetup#getSessionCharacteristics} without
+ * having called {@link #addSurface}.</p>
*
* @param surfaceGroupId A group ID for this output, used for sharing memory between multiple
* outputs.
@@ -1171,9 +1183,9 @@
* <li>from {@link android.media.MediaRecorder} by calling
* {@link android.media.MediaRecorder#getSurface} or {@link
* android.media.MediaCodec#createPersistentInputSurface}</li>
- * <li>from {@link android.media.MediaCodce} by calling
- * {@link android.media.MediaCodec#createInputSurface} or {@link
- * android.media.MediaCodec#createPersistentInputSource}</li>
+ * <li>from {@link android.media.MediaCodec} by calling
+ * {@link android.media.MediaCodec#createInputSurface} or
+ * {@link android.media.MediaCodec#createPersistentInputSurface()}</li>
* </ul>
*
* <p> If the OutputConfiguration was constructed by {@link #OutputConfiguration(int, Size)}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 3d7b714..8519722 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -548,6 +548,20 @@
}
}
+ /**
+ * Request to power a display ON or OFF.
+ * @hide
+ */
+ @RequiresPermission("android.permission.MANAGE_DISPLAYS")
+ public boolean requestDisplayPower(int displayId, boolean on) {
+ try {
+ return mDm.requestDisplayPower(displayId, on);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Error trying to request display power " + on, ex);
+ return false;
+ }
+ }
+
public void startWifiDisplayScan() {
synchronized (mLock) {
if (mWifiDisplayScanNestCount++ == 0) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 70efc6f..b7c02b0 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -236,6 +236,10 @@
@EnforcePermission("MANAGE_DISPLAYS")
void disableConnectedDisplay(int displayId);
+ // Request to power display ON or OFF.
+ @EnforcePermission("MANAGE_DISPLAYS")
+ boolean requestDisplayPower(int displayId, boolean on);
+
// Restricts display modes to specified modeIds.
@EnforcePermission("RESTRICT_DISPLAY_MODES")
void requestDisplayModes(in IBinder token, int displayId, in @nullable int[] modeIds);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 05345d8..63f0b9e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6101,6 +6101,15 @@
public static final String POINTER_SPEED = "pointer_speed";
/**
+ * Pointer scale setting.
+ *
+ * <p>This float value represents the scale by which the size of the pointer increases.
+ * @hide
+ */
+ @Readable
+ public static final String POINTER_SCALE = "pointer_scale";
+
+ /**
* Touchpad pointer speed setting.
* This is an integer value in a range between -7 and +7, so there are 15 possible values.
* -7 = slowest
@@ -6358,6 +6367,7 @@
PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
PRIVATE_SETTINGS.add(POINTER_SPEED);
PRIVATE_SETTINGS.add(POINTER_FILL_STYLE);
+ PRIVATE_SETTINGS.add(POINTER_SCALE);
PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
PRIVATE_SETTINGS.add(EGG_MODE);
PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT);
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index e1965ef..405fe26 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -29,6 +29,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.Service;
+import android.app.assist.AssistContent;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Intent;
@@ -133,6 +134,16 @@
*/
public static final String SERVICE_META_DATA = "android.content_capture";
+
+ /**
+ * Extras key to flag that the passed in {@link AssistContent} is sent only during Activity
+ * start.
+ *
+ * @hide
+ */
+ public static final String ASSIST_CONTENT_ACTIVITY_START_KEY = "activity_start_assist_content";
+
+
private final LocalDataShareAdapterResourceManager mDataShareAdapterResourceManager =
new LocalDataShareAdapterResourceManager();
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 7c2577f..c302126 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -193,6 +193,9 @@
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_END =
POINTER_ICON_VECTOR_STYLE_FILL_BLUE;
+ /** @hide */ public static final float DEFAULT_POINTER_SCALE = 1f;
+ /** @hide */ public static final float LARGE_POINTER_SCALE = 2.5f;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final int mType;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -253,7 +256,7 @@
* @hide
*/
public static @NonNull PointerIcon getLoadedSystemIcon(@NonNull Context context, int type,
- boolean useLargeIcons) {
+ boolean useLargeIcons, float pointerScale) {
if (type == TYPE_NOT_SPECIFIED) {
throw new IllegalStateException("Cannot load icon for type TYPE_NOT_SPECIFIED");
}
@@ -268,13 +271,18 @@
}
final int defStyle;
- // TODO(b/305193969): Use scaled vectors when large icons are requested.
- if (useLargeIcons) {
- defStyle = com.android.internal.R.style.LargePointer;
- } else if (android.view.flags.Flags.enableVectorCursors()) {
+ if (android.view.flags.Flags.enableVectorCursorA11ySettings()) {
defStyle = com.android.internal.R.style.VectorPointer;
} else {
- defStyle = com.android.internal.R.style.Pointer;
+ // TODO(b/346358375): Remove useLargeIcons and the legacy pointer styles when
+ // enableVectorCursorA11ySetting is rolled out.
+ if (useLargeIcons) {
+ defStyle = com.android.internal.R.style.LargePointer;
+ } else if (android.view.flags.Flags.enableVectorCursors()) {
+ defStyle = com.android.internal.R.style.VectorPointer;
+ } else {
+ defStyle = com.android.internal.R.style.Pointer;
+ }
}
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.Pointer,
@@ -286,11 +294,11 @@
Log.w(TAG, "Missing theme resources for pointer icon type " + type);
return type == TYPE_DEFAULT
? getSystemIcon(TYPE_NULL)
- : getLoadedSystemIcon(context, TYPE_DEFAULT, useLargeIcons);
+ : getLoadedSystemIcon(context, TYPE_DEFAULT, useLargeIcons, pointerScale);
}
final PointerIcon icon = new PointerIcon(type);
- icon.loadResource(context.getResources(), resourceId, context.getTheme());
+ icon.loadResource(context.getResources(), resourceId, context.getTheme(), pointerScale);
return icon;
}
@@ -353,7 +361,7 @@
}
PointerIcon icon = new PointerIcon(TYPE_CUSTOM);
- icon.loadResource(resources, resourceId, null);
+ icon.loadResource(resources, resourceId, null, DEFAULT_POINTER_SCALE);
return icon;
}
@@ -460,12 +468,13 @@
}
private BitmapDrawable getBitmapDrawableFromVectorDrawable(Resources resources,
- VectorDrawable vectorDrawable) {
+ VectorDrawable vectorDrawable, float pointerScale) {
// Ensure we pass the display metrics into the Bitmap constructor so that it is initialized
// with the correct density.
Bitmap bitmap = Bitmap.createBitmap(resources.getDisplayMetrics(),
- vectorDrawable.getIntrinsicWidth(),
- vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888, true /* hasAlpha */);
+ (int) (vectorDrawable.getIntrinsicWidth() * pointerScale),
+ (int) (vectorDrawable.getIntrinsicHeight() * pointerScale),
+ Bitmap.Config.ARGB_8888, true /* hasAlpha */);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vectorDrawable.draw(canvas);
@@ -473,7 +482,7 @@
}
private void loadResource(@NonNull Resources resources, @XmlRes int resourceId,
- @Nullable Resources.Theme theme) {
+ @Nullable Resources.Theme theme, float pointerScale) {
final XmlResourceParser parser = resources.getXml(resourceId);
final int bitmapRes;
final float hotSpotX;
@@ -484,8 +493,10 @@
final TypedArray a = resources.obtainAttributes(
parser, com.android.internal.R.styleable.PointerIcon);
bitmapRes = a.getResourceId(com.android.internal.R.styleable.PointerIcon_bitmap, 0);
- hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0);
- hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0);
+ hotSpotX = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotX, 0)
+ * pointerScale;
+ hotSpotY = a.getDimension(com.android.internal.R.styleable.PointerIcon_hotSpotY, 0)
+ * pointerScale;
a.recycle();
} catch (Exception ex) {
throw new IllegalArgumentException("Exception parsing pointer icon resource.", ex);
@@ -534,7 +545,7 @@
}
if (isVectorAnimation) {
drawableFrame = getBitmapDrawableFromVectorDrawable(resources,
- (VectorDrawable) drawableFrame);
+ (VectorDrawable) drawableFrame, pointerScale);
}
mBitmapFrames[i - 1] = getBitmapFromDrawable((BitmapDrawable) drawableFrame);
}
@@ -542,7 +553,8 @@
}
if (drawable instanceof VectorDrawable) {
mDrawNativeDropShadow = true;
- drawable = getBitmapDrawableFromVectorDrawable(resources, (VectorDrawable) drawable);
+ drawable = getBitmapDrawableFromVectorDrawable(resources, (VectorDrawable) drawable,
+ pointerScale);
}
if (!(drawable instanceof BitmapDrawable)) {
throw new IllegalArgumentException("<pointer-icon> bitmap attribute must "
diff --git a/core/java/android/view/SurfaceControlRegistry.java b/core/java/android/view/SurfaceControlRegistry.java
index 127d4a7..aa3654d 100644
--- a/core/java/android/view/SurfaceControlRegistry.java
+++ b/core/java/android/view/SurfaceControlRegistry.java
@@ -342,12 +342,14 @@
return false;
}
final boolean matchName = !sCallStackDebuggingMatchName.isEmpty();
- if (matchName && (name == null
- || !sCallStackDebuggingMatchName.contains(name.toLowerCase()))) {
- // Skip if target surface doesn't match requested surface
+ if (!matchName) {
+ return true;
+ }
+ if (name == null) {
return false;
}
- return true;
+ return sCallStackDebuggingMatchName.contains(name.toLowerCase()) ||
+ name.toLowerCase().contains(sCallStackDebuggingMatchName);
}
/**
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index bcef37f..d74867c 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -366,6 +366,14 @@
"enable_content_protection_receiver";
/**
+ * Whether AssistContent snapshot should be sent on activity start.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT =
+ "enable_activity_start_assist_content";
+
+ /**
* Sets the size of the in-memory ring buffer for the content protection flow.
*
* @hide
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index 55f2dee..00262be 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -30,7 +30,7 @@
ArrayList<Operation> mOperations;
RemoteComposeState mRemoteComposeState = new RemoteComposeState();
-
+ TimeVariables mTimeVariables = new TimeVariables();
// Semantic version of the document
Version mVersion = new Version(0, 1, 0);
@@ -70,6 +70,7 @@
public void setWidth(int width) {
this.mWidth = width;
+ mRemoteComposeState.setWindowWidth(width);
}
public int getHeight() {
@@ -78,6 +79,8 @@
public void setHeight(int height) {
this.mHeight = height;
+ mRemoteComposeState.setWindowHeight(height);
+
}
public RemoteComposeBuffer getBuffer() {
@@ -111,21 +114,21 @@
/**
* Sets the way the player handles the content
*
- * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL)
+ * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL)
* @param alignment set the alignment of the content (TOP|CENTER|BOTTOM|START|END)
- * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE)
- * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes
- * the LAYOUT modes are:
- * - LAYOUT_MATCH_PARENT
- * - LAYOUT_WRAP_CONTENT
- * or adding an horizontal mode and a vertical mode:
- * - LAYOUT_HORIZONTAL_MATCH_PARENT
- * - LAYOUT_HORIZONTAL_WRAP_CONTENT
- * - LAYOUT_HORIZONTAL_FIXED
- * - LAYOUT_VERTICAL_MATCH_PARENT
- * - LAYOUT_VERTICAL_WRAP_CONTENT
- * - LAYOUT_VERTICAL_FIXED
- * The LAYOUT_*_FIXED modes will use the intrinsic document size
+ * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE)
+ * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes
+ * the LAYOUT modes are:
+ * - LAYOUT_MATCH_PARENT
+ * - LAYOUT_WRAP_CONTENT
+ * or adding an horizontal mode and a vertical mode:
+ * - LAYOUT_HORIZONTAL_MATCH_PARENT
+ * - LAYOUT_HORIZONTAL_WRAP_CONTENT
+ * - LAYOUT_HORIZONTAL_FIXED
+ * - LAYOUT_VERTICAL_MATCH_PARENT
+ * - LAYOUT_VERTICAL_WRAP_CONTENT
+ * - LAYOUT_VERTICAL_FIXED
+ * The LAYOUT_*_FIXED modes will use the intrinsic document size
*/
public void setRootContentBehavior(int scroll, int alignment, int sizing, int mode) {
this.mContentScroll = scroll;
@@ -138,8 +141,8 @@
* Given dimensions w x h of where to paint the content, returns the corresponding scale factor
* according to the contentSizing information
*
- * @param w horizontal dimension of the rendering area
- * @param h vertical dimension of the rendering area
+ * @param w horizontal dimension of the rendering area
+ * @param h vertical dimension of the rendering area
* @param scaleOutput will contain the computed scale factor
*/
public void computeScale(float w, float h, float[] scaleOutput) {
@@ -154,37 +157,43 @@
float scale = Math.min(1f, Math.min(scaleX, scaleY));
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FIT: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
float scale = Math.min(scaleX, scaleY);
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FILL_WIDTH: {
float scale = w / mWidth;
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FILL_HEIGHT: {
float scale = h / mHeight;
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_CROP: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
float scale = Math.max(scaleX, scaleY);
contentScaleX = scale;
contentScaleY = scale;
- } break;
+ }
+ break;
case RootContentBehavior.SCALE_FILL_BOUNDS: {
float scaleX = w / mWidth;
float scaleY = h / mHeight;
contentScaleX = scaleX;
contentScaleY = scaleY;
- } break;
+ }
+ break;
default:
// nothing
}
@@ -197,10 +206,10 @@
* Given dimensions w x h of where to paint the content, returns the corresponding translation
* according to the contentAlignment information
*
- * @param w horizontal dimension of the rendering area
- * @param h vertical dimension of the rendering area
- * @param contentScaleX the horizontal scale we are going to use for the content
- * @param contentScaleY the vertical scale we are going to use for the content
+ * @param w horizontal dimension of the rendering area
+ * @param h vertical dimension of the rendering area
+ * @param contentScaleX the horizontal scale we are going to use for the content
+ * @param contentScaleY the vertical scale we are going to use for the content
* @param translateOutput will contain the computed translation
*/
private void computeTranslate(float w, float h, float contentScaleX, float contentScaleY,
@@ -215,26 +224,32 @@
switch (horizontalContentAlignment) {
case RootContentBehavior.ALIGNMENT_START: {
// nothing
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_HORIZONTAL_CENTER: {
translateX = (w - contentWidth) / 2f;
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_END: {
translateX = w - contentWidth;
- } break;
+ }
+ break;
default:
// nothing (same as alignment_start)
}
switch (verticalContentAlignment) {
case RootContentBehavior.ALIGNMENT_TOP: {
// nothing
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_VERTICAL_CENTER: {
translateY = (h - contentHeight) / 2f;
- } break;
+ }
+ break;
case RootContentBehavior.ALIGNMENT_BOTTOM: {
translateY = h - contentHeight;
- } break;
+ }
+ break;
default:
// nothing (same as alignment_top)
}
@@ -291,7 +306,13 @@
this.mMetadata = metadata;
}
- public boolean contains(float x, float y) {
+ /**
+ * Returns true if x,y coordinate is within bounds
+ * @param x x-coordinate
+ * @param y y-coordinate
+ * @return x,y coordinate is within bounds
+ */
+ public boolean contains(float x, float y) {
return x >= mLeft && x < mRight
&& y >= mTop && y < mBottom;
}
@@ -341,16 +362,22 @@
public void initializeContext(RemoteContext context) {
mRemoteComposeState.reset();
mClickAreas.clear();
-
+ mRemoteComposeState.setNextId(RemoteComposeState.START_ID);
context.mDocument = this;
context.mRemoteComposeState = mRemoteComposeState;
-
// mark context to be in DATA mode, which will skip the painting ops.
context.mMode = RemoteContext.ContextMode.DATA;
- for (Operation op: mOperations) {
+ mTimeVariables.updateTime(context);
+
+ for (Operation op : mOperations) {
+ if (op instanceof VariableSupport) {
+ ((VariableSupport) op).updateVariables(context);
+ ((VariableSupport) op).registerListening(context);
+ }
op.apply(context);
}
context.mMode = RemoteContext.ContextMode.UNSET;
+
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -375,7 +402,7 @@
* @param minorVersion minor version number, increased when adding new features
* @param patch patch level, increased upon bugfixes
*/
- void setVersion(int majorVersion, int minorVersion, int patch) {
+ void setVersion(int majorVersion, int minorVersion, int patch) {
mVersion = new Version(majorVersion, minorVersion, patch);
}
@@ -389,13 +416,13 @@
* the click coordinates will be the one reported; the order of addition of those click areas
* is therefore meaningful.
*
- * @param id the id of the area, which will be reported on click
+ * @param id the id of the area, which will be reported on click
* @param contentDescription the content description (used for accessibility)
- * @param left the left coordinate of the click area (in pixels)
- * @param top the top coordinate of the click area (in pixels)
- * @param right the right coordinate of the click area (in pixels)
- * @param bottom the bottom coordinate of the click area (in pixels)
- * @param metadata arbitrary metadata associated with the are, also reported on click
+ * @param left the left coordinate of the click area (in pixels)
+ * @param top the top coordinate of the click area (in pixels)
+ * @param right the right coordinate of the click area (in pixels)
+ * @param bottom the bottom coordinate of the click area (in pixels)
+ * @param metadata arbitrary metadata associated with the are, also reported on click
*/
public void addClickArea(int id, String contentDescription,
float left, float top, float right, float bottom, String metadata) {
@@ -417,7 +444,7 @@
* listeners.
*/
public void onClick(float x, float y) {
- for (ClickAreaRepresentation clickArea: mClickAreas) {
+ for (ClickAreaRepresentation clickArea : mClickAreas) {
if (clickArea.contains(x, y)) {
warnClickListeners(clickArea);
}
@@ -430,7 +457,7 @@
* @param id the click area id
*/
public void performClick(int id) {
- for (ClickAreaRepresentation clickArea: mClickAreas) {
+ for (ClickAreaRepresentation clickArea : mClickAreas) {
if (clickArea.mId == id) {
warnClickListeners(clickArea);
}
@@ -441,17 +468,36 @@
* Warn click listeners when a click area is activated
*/
private void warnClickListeners(ClickAreaRepresentation clickArea) {
- for (ClickCallbacks listener: mClickListeners) {
+ for (ClickCallbacks listener : mClickListeners) {
listener.click(clickArea.mId, clickArea.mMetadata);
}
}
- ///////////////////////////////////////////////////////////////////////////////////////////////
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ for (Operation op : mOperations) {
+ builder.append(op.toString());
+ builder.append("\n");
+ }
+ return builder.toString();
+ }
+
+ //////////////////////////////////////////////////////////////////////////
// Painting
- ///////////////////////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////
private final float[] mScaleOutput = new float[2];
private final float[] mTranslateOutput = new float[2];
+ private int mRepaintNext = -1; // delay to next repaint -1 = don't 1 = asap
+
+ /**
+ * Returns > 0 if it needs to repaint
+ * @return
+ */
+ public int needsRepaint() {
+ return mRepaintNext;
+ }
/**
* Paint the document
@@ -475,6 +521,11 @@
context.mPaintContext.translate(mTranslateOutput[0], mTranslateOutput[1]);
context.mPaintContext.scale(mScaleOutput[0], mScaleOutput[1]);
}
+ mTimeVariables.updateTime(context);
+ context.loadFloat(RemoteContext.ID_WINDOW_WIDTH, getWidth());
+ context.loadFloat(RemoteContext.ID_WINDOW_HEIGHT, getHeight());
+ mRepaintNext = context.updateOps();
+
for (Operation op : mOperations) {
// operations will only be executed if no theme is set (ie UNSPECIFIED)
// or the theme is equal as the one passed in argument to paint.
diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
index 54b277a..4b45ab6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java
@@ -19,6 +19,7 @@
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
+import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.DrawArc;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmap;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
@@ -28,9 +29,12 @@
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
import com.android.internal.widget.remotecompose.core.operations.DrawRect;
import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect;
+import com.android.internal.widget.remotecompose.core.operations.DrawText;
+import com.android.internal.widget.remotecompose.core.operations.DrawTextAnchored;
import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath;
-import com.android.internal.widget.remotecompose.core.operations.DrawTextRun;
import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath;
+import com.android.internal.widget.remotecompose.core.operations.FloatConstant;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.Header;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixRotate;
@@ -42,7 +46,10 @@
import com.android.internal.widget.remotecompose.core.operations.PathData;
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.TextData;
+import com.android.internal.widget.remotecompose.core.operations.TextFromFloat;
+import com.android.internal.widget.remotecompose.core.operations.TextMerge;
import com.android.internal.widget.remotecompose.core.operations.Theme;
import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
@@ -67,9 +74,10 @@
public static final int DRAW_BITMAP = 44;
public static final int DRAW_BITMAP_INT = 66;
public static final int DATA_BITMAP = 101;
+ public static final int DATA_SHADER = 45;
public static final int DATA_TEXT = 102;
-/////////////////////////////=====================
+ /////////////////////////////=====================
public static final int CLIP_PATH = 38;
public static final int CLIP_RECT = 39;
public static final int PAINT_VALUES = 40;
@@ -91,6 +99,12 @@
public static final int MATRIX_SAVE = 130;
public static final int MATRIX_RESTORE = 131;
public static final int MATRIX_SET = 132;
+ public static final int DATA_FLOAT = 80;
+ public static final int ANIMATED_FLOAT = 81;
+ public static final int DRAW_TEXT_ANCHOR = 133;
+ public static final int COLOR_EXPRESSIONS = 134;
+ public static final int TEXT_FROM_FLOAT = 135;
+ public static final int TEXT_MERGE = 136;
/////////////////////////////////////////======================
public static IntMap<CompanionOperation> map = new IntMap<>();
@@ -114,7 +128,7 @@
map.put(DRAW_RECT, DrawRect.COMPANION);
map.put(DRAW_ROUND_RECT, DrawRoundRect.COMPANION);
map.put(DRAW_TEXT_ON_PATH, DrawTextOnPath.COMPANION);
- map.put(DRAW_TEXT_RUN, DrawTextRun.COMPANION);
+ map.put(DRAW_TEXT_RUN, DrawText.COMPANION);
map.put(DRAW_TWEEN_PATH, DrawTweenPath.COMPANION);
map.put(DATA_PATH, PathData.COMPANION);
map.put(PAINT_VALUES, PaintData.COMPANION);
@@ -126,6 +140,13 @@
map.put(MATRIX_TRANSLATE, MatrixTranslate.COMPANION);
map.put(CLIP_PATH, ClipPath.COMPANION);
map.put(CLIP_RECT, ClipRect.COMPANION);
+ map.put(DATA_SHADER, ShaderData.COMPANION);
+ map.put(DATA_FLOAT, FloatConstant.COMPANION);
+ map.put(ANIMATED_FLOAT, FloatExpression.COMPANION);
+ map.put(DRAW_TEXT_ANCHOR, DrawTextAnchored.COMPANION);
+ map.put(COLOR_EXPRESSIONS, ColorExpression.COMPANION);
+ map.put(TEXT_FROM_FLOAT, TextFromFloat.COMPANION);
+ map.put(TEXT_MERGE, TextMerge.COMPANION);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
index eece8ad52..ecd0efc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java
@@ -68,7 +68,35 @@
public abstract void drawTextOnPath(int textId, int pathId, float hOffset, float vOffset);
- public abstract void drawTextRun(int textID,
+ /**
+ * Return the dimensions (left, top, right, bottom).
+ * Relative to a drawTextRun x=0, y=0;
+ *
+ * @param textId
+ * @param start
+ * @param end if end is -1 it means the whole string
+ * @param monospace measure with better support for monospace
+ * @param bounds the bounds (left, top, right, bottom)
+ */
+ public abstract void getTextBounds(int textId,
+ int start,
+ int end,
+ boolean monospace,
+ float[]bounds);
+
+ /**
+ * Draw a text starting ast x,y
+ *
+ * @param textId reference to the text
+ * @param start
+ * @param end
+ * @param contextStart
+ * @param contextEnd
+ * @param x
+ * @param y
+ * @param rtl
+ */
+ public abstract void drawTextRun(int textId,
int start,
int end,
int contextStart,
@@ -77,6 +105,14 @@
float y,
boolean rtl);
+ /**
+ * Draw an interpolation between two paths
+ * @param path1Id
+ * @param path2Id
+ * @param tween 0.0 = is path1 1.0 is path2
+ * @param start
+ * @param stop
+ */
public abstract void drawTweenPath(int path1Id,
int path2Id,
float tween,
@@ -85,21 +121,70 @@
public abstract void applyPaint(PaintBundle mPaintData);
- public abstract void mtrixScale(float scaleX, float scaleY, float centerX, float centerY);
+ /**
+ * Scale the rendering by scaleX and saleY (1.0 = no scale).
+ * Scaling is done about centerX,centerY.
+ *
+ * @param scaleX
+ * @param scaleY
+ * @param centerX
+ * @param centerY
+ */
+ public abstract void matrixScale(float scaleX, float scaleY, float centerX, float centerY);
+ /**
+ * Translate the rendering
+ * @param translateX
+ * @param translateY
+ */
public abstract void matrixTranslate(float translateX, float translateY);
+ /**
+ * Skew the rendering
+ * @param skewX
+ * @param skewY
+ */
public abstract void matrixSkew(float skewX, float skewY);
+ /**
+ * Rotate the rendering.
+ * Note rotates are cumulative.
+ * @param rotate angle to rotate
+ * @param pivotX x-coordinate about which to rotate
+ * @param pivotY y-coordinate about which to rotate
+ */
public abstract void matrixRotate(float rotate, float pivotX, float pivotY);
+ /**
+ * Save the current state of the transform
+ */
public abstract void matrixSave();
+ /**
+ * Restore the previously saved state of the transform
+ */
public abstract void matrixRestore();
+ /**
+ * Set the clip to a rectangle.
+ * Drawing outside the current clip region will have no effect
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ */
public abstract void clipRect(float left, float top, float right, float bottom);
+ /**
+ * Clip based on a path.
+ * @param pathId
+ * @param regionOp
+ */
public abstract void clipPath(int pathId, int regionOp);
+ /**
+ * Reset the paint
+ */
+ public abstract void reset();
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
index c2e8131..52fc314 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java
@@ -19,6 +19,7 @@
import com.android.internal.widget.remotecompose.core.operations.ClickArea;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
import com.android.internal.widget.remotecompose.core.operations.ClipRect;
+import com.android.internal.widget.remotecompose.core.operations.ColorExpression;
import com.android.internal.widget.remotecompose.core.operations.DrawArc;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmap;
import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt;
@@ -28,9 +29,12 @@
import com.android.internal.widget.remotecompose.core.operations.DrawPath;
import com.android.internal.widget.remotecompose.core.operations.DrawRect;
import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect;
+import com.android.internal.widget.remotecompose.core.operations.DrawText;
+import com.android.internal.widget.remotecompose.core.operations.DrawTextAnchored;
import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath;
-import com.android.internal.widget.remotecompose.core.operations.DrawTextRun;
import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath;
+import com.android.internal.widget.remotecompose.core.operations.FloatConstant;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
import com.android.internal.widget.remotecompose.core.operations.Header;
import com.android.internal.widget.remotecompose.core.operations.MatrixRestore;
import com.android.internal.widget.remotecompose.core.operations.MatrixRotate;
@@ -43,8 +47,12 @@
import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
import com.android.internal.widget.remotecompose.core.operations.RootContentDescription;
import com.android.internal.widget.remotecompose.core.operations.TextData;
+import com.android.internal.widget.remotecompose.core.operations.TextFromFloat;
+import com.android.internal.widget.remotecompose.core.operations.TextMerge;
import com.android.internal.widget.remotecompose.core.operations.Theme;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
import java.io.File;
import java.io.FileInputStream;
@@ -58,9 +66,20 @@
* Provides an abstract buffer to encode/decode RemoteCompose operations
*/
public class RemoteComposeBuffer {
+ public static final int EASING_CUBIC_STANDARD = FloatAnimation.CUBIC_STANDARD;
+ public static final int EASING_CUBIC_ACCELERATE = FloatAnimation.CUBIC_ACCELERATE;
+ public static final int EASING_CUBIC_DECELERATE = FloatAnimation.CUBIC_DECELERATE;
+ public static final int EASING_CUBIC_LINEAR = FloatAnimation.CUBIC_LINEAR;
+ public static final int EASING_CUBIC_ANTICIPATE = FloatAnimation.CUBIC_ANTICIPATE;
+ public static final int EASING_CUBIC_OVERSHOOT = FloatAnimation.CUBIC_OVERSHOOT;
+ public static final int EASING_CUBIC_CUSTOM = FloatAnimation.CUBIC_CUSTOM;
+ public static final int EASING_SPLINE_CUSTOM = FloatAnimation.SPLINE_CUSTOM;
+ public static final int EASING_EASE_OUT_BOUNCE = FloatAnimation.EASE_OUT_BOUNCE;
+ public static final int EASING_EASE_OUT_ELASTIC = FloatAnimation.EASE_OUT_ELASTIC;
WireBuffer mBuffer = new WireBuffer();
Platform mPlatform = null;
RemoteComposeState mRemoteComposeState;
+ private static final boolean DEBUG = false;
/**
* Provides an abstract buffer to encode/decode RemoteCompose operations
@@ -171,7 +190,7 @@
*
* @param text the string to inject in the buffer
*/
- int addText(String text) {
+ public int addText(String text) {
int id = mRemoteComposeState.dataGetId(text);
if (id == -1) {
id = mRemoteComposeState.cache(text);
@@ -350,7 +369,6 @@
addDrawPath(id);
}
-
/**
* Draw the specified path
*
@@ -426,12 +444,160 @@
float y,
boolean rtl) {
int textId = addText(text);
- DrawTextRun.COMPANION.apply(
+ DrawText.COMPANION.apply(
mBuffer, textId, start, end,
contextStart, contextEnd, x, y, rtl);
}
/**
+ * Draw the text, with origin at (x,y). The origin is interpreted
+ * based on the Align setting in the paint.
+ *
+ * @param textId The text to be drawn
+ * @param start The index of the first character in text to draw
+ * @param end (end - 1) is the index of the last character in text to draw
+ * @param contextStart
+ * @param contextEnd
+ * @param x The x-coordinate of the origin of the text being drawn
+ * @param y The y-coordinate of the baseline of the text being drawn
+ * @param rtl Draw RTTL
+ */
+ public void addDrawTextRun(int textId,
+ int start,
+ int end,
+ int contextStart,
+ int contextEnd,
+ float x,
+ float y,
+ boolean rtl) {
+ DrawText.COMPANION.apply(
+ mBuffer, textId, start, end,
+ contextStart, contextEnd, x, y, rtl);
+ }
+
+ /**
+ * Draw a text on canvas at relative to position (x, y),
+ * offset panX and panY.
+ * <br>
+ * The panning factors (panX, panY) mapped to the
+ * resulting bounding box of the text, in such a way that a
+ * panning factor of (0.0, 0.0) would center the text at (x, y)
+ * <ul>
+ * <li> Panning of -1.0, -1.0 - the text above & right of x,y.</li>
+ * <li>Panning of 1.0, 1.0 - the text is below and to the left</li>
+ * <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y</li>
+ * </ul>
+ * Setting panY to NaN results in y being the baseline of the text.
+ *
+ * @param text text to draw
+ * @param x Coordinate of the Anchor
+ * @param y Coordinate of the Anchor
+ * @param panX justifies text -1.0=right, 0.0=center, 1.0=left
+ * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline
+ * @param flags 1 = RTL
+ */
+ public void drawTextAnchored(String text,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+ int textId = addText(text);
+ DrawTextAnchored.COMPANION.apply(
+ mBuffer, textId,
+ x, y,
+ panX, panY,
+ flags);
+ }
+
+ /**
+ * Add a text and id so that it can be used
+ *
+ * @param text
+ * @return
+ */
+ public int createTextId(String text) {
+ return addText(text);
+ }
+
+ /**
+ * Merge two text (from id's) output one id
+ * @param id1 left id
+ * @param id2 right id
+ * @return new id that merges the two text
+ */
+ public int textMerge(int id1, int id2) {
+ int textId = addText(id1 + "+" + id2);
+ TextMerge.COMPANION.apply(mBuffer, textId, id1, id2);
+ return textId;
+ }
+
+ public static final int PAD_AFTER_SPACE = TextFromFloat.PAD_AFTER_SPACE;
+ public static final int PAD_AFTER_NONE = TextFromFloat.PAD_AFTER_NONE;
+ public static final int PAD_AFTER_ZERO = TextFromFloat.PAD_AFTER_ZERO;
+ public static final int PAD_PRE_SPACE = TextFromFloat.PAD_PRE_SPACE;
+ public static final int PAD_PRE_NONE = TextFromFloat.PAD_PRE_NONE;
+ public static final int PAD_PRE_ZERO = TextFromFloat.PAD_PRE_ZERO;
+
+ /**
+ * Create a TextFromFloat command which creates text from a Float.
+ *
+ * @param value The value to convert
+ * @param digitsBefore the digits before the decimal point
+ * @param digitsAfter the digits after the decimal point
+ * @param flags configure the behaviour using PAD_PRE_* and PAD_AFTER* flags
+ * @return id of the string that can be passed to drawTextAnchored
+ */
+ public int createTextFromFloat(float value, short digitsBefore,
+ short digitsAfter, int flags) {
+ String placeHolder = Utils.floatToString(value)
+ + "(" + digitsBefore + "," + digitsAfter + "," + flags + ")";
+ int id = mRemoteComposeState.dataGetId(placeHolder);
+ if (id == -1) {
+ id = mRemoteComposeState.cache(placeHolder);
+ // TextData.COMPANION.apply(mBuffer, id, text);
+ }
+ TextFromFloat.COMPANION.apply(mBuffer, id, value, digitsBefore,
+ digitsAfter, flags);
+ return id;
+ }
+
+ /**
+ * Draw a text on canvas at relative to position (x, y),
+ * offset panX and panY.
+ * <br>
+ * The panning factors (panX, panY) mapped to the
+ * resulting bounding box of the text, in such a way that a
+ * panning factor of (0.0, 0.0) would center the text at (x, y)
+ * <ul>
+ * <li> Panning of -1.0, -1.0 - the text above & right of x,y.</li>
+ * <li>Panning of 1.0, 1.0 - the text is below and to the left</li>
+ * <li>Panning of 1.0, 0.0 - the test is centered & to the right of x,y</li>
+ * </ul>
+ * Setting panY to NaN results in y being the baseline of the text.
+ *
+ * @param textId text to draw
+ * @param x Coordinate of the Anchor
+ * @param y Coordinate of the Anchor
+ * @param panX justifies text -1.0=right, 0.0=center, 1.0=left
+ * @param panY position text -1.0=above, 0.0=center, 1.0=below, Nan=baseline
+ * @param flags 1 = RTL
+ */
+ public void drawTextAnchored(int textId,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+
+ DrawTextAnchored.COMPANION.apply(
+ mBuffer, textId,
+ x, y,
+ panX, panY,
+ flags);
+ }
+
+ /**
* draw an interpolation between two paths that have the same pattern
* <p>
* Warning paths objects are not immutable and this is not taken into consideration
@@ -490,6 +656,10 @@
return id;
}
+ /**
+ * Adds a paint Bundle to the doc
+ * @param paint
+ */
public void addPaint(PaintBundle paint) {
PaintData.COMPANION.apply(mBuffer, paint);
}
@@ -499,7 +669,9 @@
mBuffer.setIndex(0);
while (mBuffer.available()) {
int opId = mBuffer.readByte();
- System.out.println(">>> " + opId);
+ if (DEBUG) {
+ Utils.log(">> " + opId);
+ }
CompanionOperation operation = Operations.map.get(opId);
if (operation == null) {
throw new RuntimeException("Unknown operation encountered " + opId);
@@ -519,7 +691,6 @@
Theme.COMPANION.apply(mBuffer, theme);
}
-
static String version() {
return "v1.0";
}
@@ -654,8 +825,8 @@
/**
* Add a pre-concat of the current matrix with the specified scale.
*
- * @param scaleX The amount to scale in X
- * @param scaleY The amount to scale in Y
+ * @param scaleX The amount to scale in X
+ * @param scaleY The amount to scale in Y
*/
public void addMatrixScale(float scaleX, float scaleY) {
MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, Float.NaN, Float.NaN);
@@ -673,12 +844,174 @@
MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, centerX, centerY);
}
+ /**
+ * sets the clip based on clip id
+ * @param pathId 0 clears the clip
+ */
public void addClipPath(int pathId) {
ClipPath.COMPANION.apply(mBuffer, pathId);
}
+ /**
+ * Sets the clip based on clip rec
+ * @param left
+ * @param top
+ * @param right
+ * @param bottom
+ */
public void addClipRect(float left, float top, float right, float bottom) {
ClipRect.COMPANION.apply(mBuffer, left, top, right, bottom);
}
+
+ /**
+ * Add a float return a NaN number pointing to that float
+ * @param value
+ * @return
+ */
+ public float addFloat(float value) {
+ int id = mRemoteComposeState.cacheFloat(value);
+ FloatConstant.COMPANION.apply(mBuffer, id, value);
+ return Utils.asNan(id);
+ }
+
+ /**
+ * Add a float that is a computation based on variables
+ * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7
+ * @return NaN id of the result of the calculation
+ */
+ public float addAnimatedFloat(float... value) {
+ int id = mRemoteComposeState.cache(value);
+ FloatExpression.COMPANION.apply(mBuffer, id, value, null);
+ return Utils.asNan(id);
+ }
+
+ /**
+ * Add a float that is a computation based on variables.
+ * see packAnimation
+ * @param value A RPN style float operation i.e. "4, 3, ADD" outputs 7
+ * @param animation Array of floats that represents animation
+ * @return NaN id of the result of the calculation
+ */
+ public float addAnimatedFloat(float[] value, float[] animation) {
+ int id = mRemoteComposeState.cache(value);
+ FloatExpression.COMPANION.apply(mBuffer, id, value, animation);
+ return Utils.asNan(id);
+ }
+
+ /**
+ * Add a color that represents the tween between two colors
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(int color1, int color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 0, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Add a color that represents the tween between two colors where color1
+ * is the id of a color
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(short color1, int color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 1, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Add a color that represents the tween between two colors where color2
+ * is the id of a color
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(int color1, short color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 2, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Add a color that represents the tween between two colors where color1 &
+ * color2 are the ids of colors
+ * @param color1
+ * @param color2
+ * @param tween
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(short color1, short color2, float tween) {
+ ColorExpression c = new ColorExpression(0, 3, color1, color2, tween);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Color calculated by Hue saturation and value.
+ * (as floats they can be variables used to create color transitions)
+ * @param hue
+ * @param sat
+ * @param value
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(float hue, float sat, float value) {
+ ColorExpression c = new ColorExpression(0, hue, sat, value);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * Color calculated by Alpha, Hue saturation and value.
+ * (as floats they can be variables used to create color transitions)
+ * @param alpha
+ * @param hue
+ * @param sat
+ * @param value
+ * @return id of the color (color ids are short)
+ */
+ public short addColorExpression(int alpha, float hue, float sat, float value) {
+ ColorExpression c = new ColorExpression(0, alpha, hue, sat, value);
+ short id = (short) mRemoteComposeState.cache(c);
+ c.mId = id;
+ c.write(mBuffer);
+ return id;
+ }
+
+ /**
+ * create and animation based on description and return as an array of
+ * floats. see addAnimatedFloat
+ * @param duration
+ * @param type
+ * @param spec
+ * @param initialValue
+ * @param wrap
+ * @return
+ */
+ public static float[] packAnimation(float duration,
+ int type,
+ float[] spec,
+ float initialValue,
+ float wrap) {
+
+ return FloatAnimation.packToFloatArray(duration, type, spec, initialValue, wrap);
+ }
+
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index 17e8c83..66a37e67 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -15,26 +15,53 @@
*/
package com.android.internal.widget.remotecompose.core;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_CONTINUOUS_SEC;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_TIME_IN_MIN;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_TIME_IN_SEC;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_WINDOW_HEIGHT;
+import static com.android.internal.widget.remotecompose.core.RemoteContext.ID_WINDOW_WIDTH;
+
import com.android.internal.widget.remotecompose.core.operations.utilities.IntMap;
+import java.util.ArrayList;
import java.util.HashMap;
/**
* Represents runtime state for a RemoteCompose document
+ * State includes things like the value of variables
*/
public class RemoteComposeState {
-
+ public static final int START_ID = 42;
+ private static final int MAX_FLOATS = 500;
private final IntMap<Object> mIntDataMap = new IntMap<>();
private final IntMap<Boolean> mIntWrittenMap = new IntMap<>();
private final HashMap<Object, Integer> mDataIntMap = new HashMap();
+ private final float[] mFloatMap = new float[MAX_FLOATS]; // efficient cache
+ private final int[] mColorMap = new int[MAX_FLOATS]; // efficient cache
+ private int mNextId = START_ID;
- private static int sNextId = 42;
+ {
+ for (int i = 0; i < mFloatMap.length; i++) {
+ mFloatMap[i] = Float.NaN;
+ }
+ }
- public Object getFromId(int id) {
+ /**
+ * Get Object based on id. The system will cache things like bitmaps
+ * Paths etc. They can be accessed with this command
+ * @param id
+ * @return
+ */
+ public Object getFromId(int id) {
return mIntDataMap.get(id);
}
- public boolean containsId(int id) {
+ /**
+ * true if the cache contain this id
+ * @param id
+ * @return
+ */
+ public boolean containsId(int id) {
return mIntDataMap.get(id) != null;
}
@@ -69,6 +96,65 @@
}
/**
+ * Insert an item in the cache
+ */
+ public void update(int id, Object item) {
+ mDataIntMap.remove(mIntDataMap.get(id));
+ mDataIntMap.put(item, id);
+ mIntDataMap.put(id, item);
+ }
+
+ /**
+ * Insert an item in the cache
+ */
+ public int cacheFloat(float item) {
+ int id = nextId();
+ mFloatMap[id] = item;
+ return id;
+ }
+
+ /**
+ * Insert an item in the cache
+ */
+ public void cacheFloat(int id, float item) {
+ mFloatMap[id] = item;
+ }
+
+ /**
+ * Insert an item in the cache
+ */
+ public void updateFloat(int id, float item) {
+ mFloatMap[id] = item;
+ }
+
+ /**
+ * get float
+ */
+ public float getFloat(int id) {
+ return mFloatMap[id];
+ }
+
+ /**
+ * Get the float value
+ *
+ * @param id
+ * @return
+ */
+ public int getColor(int id) {
+ return mColorMap[id];
+ }
+
+ /**
+ * Modify the color at id.
+ * @param id
+ * @param color
+ */
+ public void updateColor(int id, int color) {
+ mColorMap[id] = color;
+ }
+
+
+ /**
* Method to determine if a cached value has been written to the documents WireBuffer based on
* its id.
*/
@@ -79,22 +165,90 @@
/**
* Method to mark that a value, represented by its id, has been written to the WireBuffer
*/
- public void markWritten(int id) {
+ public void markWritten(int id) {
mIntWrittenMap.put(id, true);
}
/**
- * Clear the record of the values that have been written to the WireBuffer.
+ * Clear the record of the values that have been written to the WireBuffer.
*/
void reset() {
mIntWrittenMap.clear();
}
- public static int nextId() {
- return sNextId++;
+ /**
+ * Get the next available id
+ * @return
+ */
+ public int nextId() {
+ return mNextId++;
}
- public static void setNextId(int id) {
- sNextId = id;
+
+ /**
+ * Set the next id
+ * @param id
+ */
+ public void setNextId(int id) {
+ mNextId = id;
+ }
+
+ IntMap<ArrayList<VariableSupport>> mVarListeners = new IntMap<>();
+ ArrayList<VariableSupport> mAllVarListeners = new ArrayList<>();
+
+ private void add(int id, VariableSupport variableSupport) {
+ ArrayList<VariableSupport> v = mVarListeners.get(id);
+ if (v == null) {
+ v = new ArrayList<VariableSupport>();
+ mVarListeners.put(id, v);
+ }
+ v.add(variableSupport);
+ mAllVarListeners.add(variableSupport);
+ }
+
+ /**
+ * Commands that listen to variables add themselves.
+ * @param id
+ * @param variableSupport
+ */
+ public void listenToVar(int id, VariableSupport variableSupport) {
+ add(id, variableSupport);
+ }
+
+ /**
+ * List of Commands that need to be updated
+ * @param context
+ * @return
+ */
+ public int getOpsToUpdate(RemoteContext context) {
+ for (VariableSupport vs : mAllVarListeners) {
+ vs.updateVariables(context);
+ }
+ if (mVarListeners.get(ID_CONTINUOUS_SEC) != null) {
+ return 1;
+ }
+ if (mVarListeners.get(ID_TIME_IN_SEC) != null) {
+ return 1000;
+ }
+ if (mVarListeners.get(ID_TIME_IN_MIN) != null) {
+ return 1000 * 60;
+ }
+ return -1;
+ }
+
+ /**
+ * Set the width of the overall document on screen.
+ * @param width
+ */
+ public void setWindowWidth(float width) {
+ updateFloat(ID_WINDOW_WIDTH, width);
+ }
+
+ /**
+ * Set the width of the overall document on screen.
+ * @param height
+ */
+ public void setWindowHeight(float height) {
+ updateFloat(ID_WINDOW_HEIGHT, height);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index d16cbc5..7e72168 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,10 @@
*/
package com.android.internal.widget.remotecompose.core;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
import com.android.internal.widget.remotecompose.core.operations.Theme;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
/**
* Specify an abstract context used to playback RemoteCompose documents
@@ -27,7 +30,7 @@
public abstract class RemoteContext {
protected CoreDocument mDocument;
public RemoteComposeState mRemoteComposeState;
-
+ long mStart = System.nanoTime(); // todo This should be set at a hi level
protected PaintContext mPaintContext = null;
ContextMode mMode = ContextMode.UNSET;
@@ -37,9 +40,40 @@
public float mWidth = 0f;
public float mHeight = 0f;
+ /**
+ * Load a path under an id.
+ * Paths can be use in clip drawPath and drawTweenPath
+ * @param instanceId
+ * @param floatPath
+ */
public abstract void loadPathData(int instanceId, float[] floatPath);
/**
+ * Associate a name with a give id.
+ *
+ * @param varName
+ * @param varId
+ * @param varType
+ */
+ public abstract void loadVariableName(String varName, int varId, int varType);
+
+ /**
+ * Save a color under a given id
+ * @param id
+ * @param color
+ */
+ public abstract void loadColor(int id, int color);
+
+ /**
+ * gets the time animation clock as float in seconds
+ * @return a monotonic time in seconds (arbitrary zero point)
+ */
+ public float getAnimationTime() {
+ return (System.nanoTime() - mStart) * 1E-9f;
+ }
+
+
+ /**
* The context can be used in a few different mode, allowing operations to skip being executed:
* - UNSET : all operations will get executed
* - DATA : only operations dealing with DATA (eg loading a bitmap) should execute
@@ -96,6 +130,8 @@
public void header(int majorVersion, int minorVersion, int patchVersion,
int width, int height, long capabilities
) {
+ mRemoteComposeState.setWindowWidth(width);
+ mRemoteComposeState.setWindowHeight(height);
mDocument.setVersion(majorVersion, minorVersion, patchVersion);
mDocument.setWidth(width);
mDocument.setHeight(height);
@@ -137,9 +173,105 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// Data handling
///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Save a bitmap under an imageId
+ * @param imageId
+ * @param width
+ * @param height
+ * @param bitmap
+ */
public abstract void loadBitmap(int imageId, int width, int height, byte[] bitmap);
+
+ /**
+ * Save a string under a given id
+ * @param id
+ * @param text
+ */
public abstract void loadText(int id, String text);
+ /**
+ * Get a string given an id
+ * @param id
+ * @return
+ */
+ public abstract String getText(int id);
+
+ /**
+ * Load a float
+ * @param id
+ * @param value
+ */
+ public abstract void loadFloat(int id, float value);
+
+ /**
+ * Load an animated float associated with an id
+ * Todo: Remove?
+ * @param id
+ * @param animatedFloat
+ */
+ public abstract void loadAnimatedFloat(int id, FloatExpression animatedFloat);
+
+ /**
+ * Save a shader under and ID
+ * @param id
+ * @param value
+ */
+ public abstract void loadShader(int id, ShaderData value);
+
+ /**
+ * Get a float given an id
+ * @param id
+ * @return
+ */
+ public abstract float getFloat(int id);
+
+ /**
+ * Get the color given and ID
+ * @param id
+ * @return
+ */
+ public abstract int getColor(int id);
+
+ /**
+ * called to notify system that a command is interested in a variable
+ * @param id
+ * @param variableSupport
+ */
+ public abstract void listensTo(int id, VariableSupport variableSupport);
+
+ /**
+ * Notify commands with variables have changed
+ * @return
+ */
+ public abstract int updateOps();
+
+ /**
+ * Get a shader given the id
+ * @param id
+ * @return
+ */
+ public abstract ShaderData getShader(int id);
+
+ public static final int ID_CONTINUOUS_SEC = 1;
+ public static final int ID_TIME_IN_SEC = 2;
+ public static final int ID_TIME_IN_MIN = 3;
+ public static final int ID_TIME_IN_HR = 4;
+ public static final int ID_WINDOW_WIDTH = 5;
+ public static final int ID_WINDOW_HEIGHT = 6;
+ public static final int ID_COMPONENT_WIDTH = 7;
+ public static final int ID_COMPONENT_HEIGHT = 8;
+ public static final int ID_CALENDAR_MONTH = 9;
+
+ public static final float FLOAT_CONTINUOUS_SEC = Utils.asNan(ID_CONTINUOUS_SEC);
+ public static final float FLOAT_TIME_IN_SEC = Utils.asNan(ID_TIME_IN_SEC);
+ public static final float FLOAT_TIME_IN_MIN = Utils.asNan(ID_TIME_IN_MIN);
+ public static final float FLOAT_TIME_IN_HR = Utils.asNan(ID_TIME_IN_HR);
+ public static final float FLOAT_CALENDAR_MONTH = Utils.asNan(ID_CALENDAR_MONTH);
+ public static final float FLOAT_WINDOW_WIDTH = Utils.asNan(ID_WINDOW_WIDTH);
+ public static final float FLOAT_WINDOW_HEIGHT = Utils.asNan(ID_WINDOW_HEIGHT);
+ public static final float FLOAT_COMPONENT_WIDTH = Utils.asNan(ID_COMPONENT_WIDTH);
+ public static final float FLOAT_COMPONENT_HEIGHT = Utils.asNan(ID_COMPONENT_HEIGHT);
///////////////////////////////////////////////////////////////////////////////////////////////
// Click handling
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
new file mode 100644
index 0000000..e9708b7
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core;
+
+import java.time.LocalDateTime;
+
+/**
+ * This generates the standard system variables for time.
+ */
+public class TimeVariables {
+ /**
+ * This class populates all time variables in the system
+ * @param context
+ */
+ public void updateTime(RemoteContext context) {
+ LocalDateTime dateTime = LocalDateTime.now();
+ // This define the time in the format
+ // seconds run from Midnight=0 quantized to seconds hour 0..3599
+ // minutes run from Midnight=0 quantized to minutes 0..1439
+ // hours run from Midnight=0 quantized to Hours 0-23
+ // CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600
+ // CONTINUOUS_SEC is accurate to milliseconds due to float precession
+ int month = dateTime.getDayOfMonth();
+ int hour = dateTime.getHour();
+ int minute = dateTime.getMinute();
+ int seconds = dateTime.getSecond();
+ int currentMinute = hour * 60 + minute;
+ int currentSeconds = minute * 60 + seconds;
+ float sec = currentSeconds + dateTime.getNano() * 1E-9f;
+
+ context.loadFloat(RemoteContext.ID_CONTINUOUS_SEC, sec);
+ context.loadFloat(RemoteContext.ID_TIME_IN_SEC, currentSeconds);
+ context.loadFloat(RemoteContext.ID_TIME_IN_MIN, currentMinute);
+ context.loadFloat(RemoteContext.ID_TIME_IN_HR, hour);
+ context.loadFloat(RemoteContext.ID_CALENDAR_MONTH, month);
+
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
new file mode 100644
index 0000000..d59b1bc
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/VariableSupport.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core;
+
+/**
+ * Interface for operators that interact with variables
+ * Threw this they register to listen to particular variables
+ * and are notified when they change
+ */
+public interface VariableSupport {
+ /**
+ * Call to allow an operator to register interest in variables.
+ * Typically they call context.listensTo(id, this)
+ * @param context
+ */
+ void registerListening(RemoteContext context);
+
+ /**
+ * Called to be notified that the variables you are interested have changed.
+ * @param context
+ */
+ void updateVariables(RemoteContext context);
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
index 76b7144..f186322 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/BitmapData.java
@@ -51,11 +51,12 @@
@Override
public String toString() {
- return "BITMAP DATA $imageId";
+ return "BITMAP DATA " + mImageId;
}
public static class Companion implements CompanionOperation {
- private Companion() {}
+ private Companion() {
+ }
@Override
public String name() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
index 8d4a787..e6d5fe7 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java
@@ -24,6 +24,11 @@
import java.util.List;
+/**
+ * Defines a path that clips a the subsequent drawing commands
+ * Use MatrixSave and MatrixRestore commands to remove clip
+ * TODO allow id 0 to mean null?
+ */
public class ClipPath extends PaintOperation {
public static final Companion COMPANION = new Companion();
int mId;
@@ -93,5 +98,4 @@
public void paint(PaintContext context) {
context.clipPath(mId, mRegionOp);
}
-}
-
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
index 803618a..613eceb 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java
@@ -15,88 +15,36 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class ClipRect extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
+/**
+ * Support clip with a rectangle
+ */
+public class ClipRect extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.CLIP_RECT) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new ClipRect(x1, y1, x2, y2);
+ }
+ };
public ClipRect(
float left,
float top,
float right,
float bottom) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
-
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
- }
-
- @Override
- public String toString() {
- return "ClipRect " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
-
- ClipRect op = new ClipRect(sLeft, srcTop, srcRight, srcBottom);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "ClipRect";
- }
-
- @Override
- public int id() {
- return Operations.CLIP_RECT;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom) {
- buffer.start(Operations.CLIP_RECT);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- }
+ super(left, top, right, bottom);
+ mName = "ClipRect";
}
@Override
public void paint(PaintContext context) {
- context.clipRect(mLeft,
- mTop,
- mRight,
- mBottom);
+ context.clipRect(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
new file mode 100644
index 0000000..7d28cea
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ColorExpression.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to Colors
+ * Color modes
+ * mMode = 0 two colors and a tween
+ * mMode = 1 color1 is a colorID.
+ * mMode = 2 color2 is a colorID.
+ * mMode = 3 color1 & color2 are ids
+ * mMode = 4 H S V mode
+ */
+public class ColorExpression implements Operation, VariableSupport {
+ public int mId;
+ int mMode;
+ public int mColor1;
+ public int mColor2;
+ public float mTween = 0.0f;
+
+
+ public float mHue = 0; // only in Mode 4
+ public float mSat = 0;
+ public float mValue = 0;
+ public float mOutHue = 0; // only in Mode 4
+ public float mOutSat = 0;
+ public float mOutValue = 0;
+ public int mAlpha = 0xFF; // only used in hsv mode
+
+ public float mOutTween = 0.0f;
+ public int mOutColor1;
+ public int mOutColor2;
+ public static final Companion COMPANION = new Companion();
+ public static final int HSV_MODE = 4;
+ public ColorExpression(int id, float hue, float sat, float value) {
+ mMode = HSV_MODE;
+ mAlpha = 0xFF;
+ mOutHue = mHue = hue;
+ mOutSat = mSat = sat;
+ mOutValue = mValue = value;
+ mColor1 = Float.floatToRawIntBits(hue);
+ mColor2 = Float.floatToRawIntBits(sat);
+ mTween = value;
+ }
+ public ColorExpression(int id, int alpha, float hue, float sat, float value) {
+ mMode = HSV_MODE;
+ mAlpha = alpha;
+ mOutHue = mHue = hue;
+ mOutSat = mSat = sat;
+ mOutValue = mValue = value;
+ mColor1 = Float.floatToRawIntBits(hue);
+ mColor2 = Float.floatToRawIntBits(sat);
+ mTween = value;
+ }
+
+ public ColorExpression(int id, int mode, int color1, int color2, float tween) {
+ this.mId = id;
+ this.mMode = mode & 0xFF;
+ this.mAlpha = (mode >> 16) & 0xFF;
+ if (mMode == HSV_MODE) {
+ mOutHue = mHue = Float.intBitsToFloat(color1);
+ mOutSat = mSat = Float.intBitsToFloat(color2);
+ mOutValue = mValue = tween;
+ }
+ this.mColor1 = color1;
+ this.mColor2 = color2;
+ this.mTween = tween;
+ this.mOutTween = tween;
+ this.mOutColor1 = color1;
+ this.mOutColor2 = color2;
+
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ if (mMode == 4) {
+ if (Float.isNaN(mHue)) {
+ mOutHue = context.getFloat(Utils.idFromNan(mHue));
+ }
+ if (Float.isNaN(mSat)) {
+ mOutSat = context.getFloat(Utils.idFromNan(mSat));
+ }
+ if (Float.isNaN(mValue)) {
+ mOutValue = context.getFloat(Utils.idFromNan(mValue));
+ }
+ }
+ if (Float.isNaN(mTween)) {
+ mOutTween = context.getFloat(Utils.idFromNan(mTween));
+ }
+ if ((mMode & 1) == 1) {
+ mOutColor1 = context.getColor(mColor1);
+ }
+ if ((mMode & 2) == 2) {
+ mOutColor2 = context.getColor(mColor2);
+ }
+ }
+
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (mMode == 4) {
+ if (Float.isNaN(mHue)) {
+ context.listensTo(Utils.idFromNan(mHue), this);
+ }
+ if (Float.isNaN(mSat)) {
+ context.listensTo(Utils.idFromNan(mSat), this);
+ }
+ if (Float.isNaN(mValue)) {
+ context.listensTo(Utils.idFromNan(mValue), this);
+ }
+ return;
+ }
+ if (Float.isNaN(mTween)) {
+ context.listensTo(Utils.idFromNan(mTween), this);
+ }
+ if ((mMode & 1) == 1) {
+ context.listensTo(mColor1, this);
+ }
+ if ((mMode & 2) == 2) {
+ context.listensTo(mColor2, this);
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ if (mMode == 4) {
+ context.loadColor(mId, (mAlpha << 24)
+ | (0xFFFFFF & Utils.hsvToRgb(mOutHue, mOutSat, mOutValue)));
+ return;
+ }
+ if (mOutTween == 0.0) {
+ context.loadColor(mId, mColor1);
+ } else {
+ if ((mMode & 1) == 1) {
+ mOutColor1 = context.getColor(mColor1);
+ }
+ if ((mMode & 2) == 2) {
+ mOutColor2 = context.getColor(mColor2);
+ }
+
+ context.loadColor(mId,
+ Utils.interpolateColor(mOutColor1, mOutColor2, mOutTween));
+ }
+
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ int mode = mMode | (mAlpha << 16);
+ COMPANION.apply(buffer, mId, mode, mColor1, mColor2, mTween);
+ }
+
+ @Override
+ public String toString() {
+ if (mMode == 4) {
+ return "ColorExpression[" + mId + "] = hsv (" + Utils.floatToString(mHue)
+ + ", " + Utils.floatToString(mSat)
+ + ", " + Utils.floatToString(mValue) + ")";
+ }
+
+ String c1 = (mMode & 1) == 1 ? "[" + mColor1 + "]" : Utils.colorInt(mColor1);
+ String c2 = (mMode & 2) == 2 ? "[" + mColor2 + "]" : Utils.colorInt(mColor2);
+ return "ColorExpression[" + mId + "] = tween(" + c1
+ + ", " + c2 + ", "
+ + Utils.floatToString(mTween) + ")";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "ColorExpression";
+ }
+
+ @Override
+ public int id() {
+ return Operations.COLOR_EXPRESSIONS;
+ }
+
+ /**
+ * Call to write a ColorExpression object on the buffer
+ * @param buffer
+ * @param id of the ColorExpression object
+ * @param mode if colors are id or actual values
+ * @param color1
+ * @param color2
+ * @param tween
+ */
+ public void apply(WireBuffer buffer,
+ int id, int mode,
+ int color1, int color2, float tween) {
+ buffer.start(Operations.COLOR_EXPRESSIONS);
+ buffer.writeInt(id);
+ buffer.writeInt(mode);
+ buffer.writeInt(color1);
+ buffer.writeInt(color2);
+ buffer.writeFloat(tween);
+
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int id = buffer.readInt();
+ int mode = buffer.readInt();
+ int color1 = buffer.readInt();
+ int color2 = buffer.readInt();
+ float tween = buffer.readFloat();
+
+ operations.add(new ColorExpression(id, mode, color1, color2, tween));
+ }
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
index e829975..c176864 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java
@@ -15,107 +15,36 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
+public class DrawArc extends DrawBase6 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_ARC) {
+ @Override
+ public Operation construct(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ return new DrawArc(v1, v2, v3, v4, v5, v6);
+ }
+ };
-public class DrawArc extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
- float mStartAngle;
- float mSweepAngle;
-
- public DrawArc(
- float left,
- float top,
- float right,
- float bottom,
- float startAngle,
- float sweepAngle) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- mStartAngle = startAngle;
- mSweepAngle = sweepAngle;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft,
- mTop,
- mRight,
- mBottom,
- mStartAngle,
- mSweepAngle);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + " "
- + "- " + mStartAngle + " " + mSweepAngle + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
- float mStartAngle = buffer.readFloat();
- float mSweepAngle = buffer.readFloat();
- DrawArc op = new DrawArc(sLeft, srcTop, srcRight, srcBottom,
- mStartAngle, mSweepAngle);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawArc";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_ARC;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom,
- float startAngle,
- float sweepAngle) {
- buffer.start(Operations.DRAW_ARC);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- buffer.writeFloat(startAngle);
- buffer.writeFloat(sweepAngle);
- }
+ public DrawArc(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ super(v1, v2, v3, v4, v5, v6);
+ mName = "DrawArc";
}
@Override
public void paint(PaintContext context) {
- context.drawArc(mLeft,
- mTop,
- mRight,
- mBottom,
- mStartAngle,
- mSweepAngle);
+ context.drawArc(mV1, mV2, mV3, mV4, mV5, mV6);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
new file mode 100644
index 0000000..0963c13
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase2.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for commands that take 3 float
+ */
+public abstract class DrawBase2 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_CIRCLE) {
+ @Override
+ public Operation construct(float x1, float y1) {
+ // subclass should return new DrawX(x1, y1);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mV1;
+ float mV2;
+ float mValue1;
+ float mValue2;
+
+ public DrawBase2(float v1, float v2) {
+ mValue1 = v1;
+ mValue2 = v2;
+ mV1 = v1;
+ mV2 = v2;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mV1 = (Float.isNaN(mValue1))
+ ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
+ mV2 = (Float.isNaN(mValue2))
+ ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue1)) {
+ context.listensTo(Utils.idFromNan(mValue1), this);
+ }
+ if (Float.isNaN(mValue2)) {
+ context.listensTo(Utils.idFromNan(mValue2), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mV1, mV2);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mV1) + " " + floatToString(mV2);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float v1 = buffer.readFloat();
+ float v2 = buffer.readFloat();
+
+ Operation op = construct(v1, v2);
+ operations.add(op);
+ }
+
+ /**
+ * Override to construct a 2 float value operation
+ * @param x1
+ * @param y1
+ * @return
+ */
+ public Operation construct(float x1, float y1) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param x1
+ * @param y1
+ */
+ public void apply(WireBuffer buffer,
+ float x1,
+ float y1) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(x1);
+ buffer.writeFloat(y1);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
new file mode 100644
index 0000000..56b2f1f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase3.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for commands that take 3 float
+ */
+public abstract class DrawBase3 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_CIRCLE) {
+ @Override
+ public Operation construct(float x1, float y1, float x2) {
+ // subclass should return new DrawX(x1, y1, x2, y2);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mV1;
+ float mV2;
+ float mV3;
+ float mValue1;
+ float mValue2;
+ float mValue3;
+
+ public DrawBase3(
+ float v1,
+ float v2,
+ float v3) {
+ mValue1 = v1;
+ mValue2 = v2;
+ mValue3 = v3;
+
+ mV1 = v1;
+ mV2 = v2;
+ mV3 = v3;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mV1 = (Float.isNaN(mValue1))
+ ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
+ mV2 = (Float.isNaN(mValue2))
+ ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
+ mV3 = (Float.isNaN(mValue3))
+ ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue1)) {
+ context.listensTo(Utils.idFromNan(mValue1), this);
+ }
+ if (Float.isNaN(mValue2)) {
+ context.listensTo(Utils.idFromNan(mValue2), this);
+ }
+ if (Float.isNaN(mValue3)) {
+ context.listensTo(Utils.idFromNan(mValue3), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mV1, mV2, mV3);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mV1) + " " + floatToString(mV2)
+ + " " + floatToString(mV3);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float v1 = buffer.readFloat();
+ float v2 = buffer.readFloat();
+ float v3 = buffer.readFloat();
+
+ Operation op = construct(v1, v2, v3);
+ operations.add(op);
+ }
+
+ /**
+ * Construct and Operation from the 3 variables.
+ * This must be overridden by subclasses
+ * @param x1
+ * @param y1
+ * @param x2
+ * @return
+ */
+ public Operation construct(float x1,
+ float y1,
+ float x2) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param x1
+ * @param y1
+ * @param x2
+ */
+ public void apply(WireBuffer buffer,
+ float x1,
+ float y1,
+ float x2) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(x1);
+ buffer.writeFloat(y1);
+ buffer.writeFloat(x2);
+
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
new file mode 100644
index 0000000..ec35a16
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase4.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for draw commands that take 4 floats
+ */
+public abstract class DrawBase4 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_RECT) {
+ @Override
+ public Operation construct(float x1, float y1, float x2, float y2) {
+ // return new DrawRectBase(x1, y1, x2, y2);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mX1;
+ float mY1;
+ float mX2;
+ float mY2;
+ float mX1Value;
+ float mY1Value;
+ float mX2Value;
+ float mY2Value;
+
+ public DrawBase4(
+ float x1,
+ float y1,
+ float x2,
+ float y2) {
+ mX1Value = x1;
+ mY1Value = y1;
+ mX2Value = x2;
+ mY2Value = y2;
+
+ mX1 = x1;
+ mY1 = y1;
+ mX2 = x2;
+ mY2 = y2;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mX1 = (Float.isNaN(mX1Value))
+ ? context.getFloat(Utils.idFromNan(mX1Value)) : mX1Value;
+ mY1 = (Float.isNaN(mY1Value))
+ ? context.getFloat(Utils.idFromNan(mY1Value)) : mY1Value;
+ mX2 = (Float.isNaN(mX2Value))
+ ? context.getFloat(Utils.idFromNan(mX2Value)) : mX2Value;
+ mY2 = (Float.isNaN(mY2Value))
+ ? context.getFloat(Utils.idFromNan(mY2Value)) : mY2Value;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mX1Value)) {
+ context.listensTo(Utils.idFromNan(mX1Value), this);
+ }
+ if (Float.isNaN(mY1Value)) {
+ context.listensTo(Utils.idFromNan(mY1Value), this);
+ }
+ if (Float.isNaN(mX2Value)) {
+ context.listensTo(Utils.idFromNan(mX2Value), this);
+ }
+ if (Float.isNaN(mY2Value)) {
+ context.listensTo(Utils.idFromNan(mY2Value), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mX1, mY1, mX2, mY2);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mX1Value, mX1) + " " + floatToString(mY1Value, mY1)
+ + " " + floatToString(mX2Value, mX2) + " " + floatToString(mY2Value, mY2);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sLeft = buffer.readFloat();
+ float srcTop = buffer.readFloat();
+ float srcRight = buffer.readFloat();
+ float srcBottom = buffer.readFloat();
+
+ Operation op = construct(sLeft, srcTop, srcRight, srcBottom);
+ operations.add(op);
+ }
+
+ /**
+ * Construct and Operation from the 3 variables.
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ * @return
+ */
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param x1
+ * @param y1
+ * @param x2
+ * @param y2
+ */
+ public void apply(WireBuffer buffer,
+ float x1,
+ float y1,
+ float x2,
+ float y2) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(x1);
+ buffer.writeFloat(y1);
+ buffer.writeFloat(x2);
+ buffer.writeFloat(y2);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
new file mode 100644
index 0000000..2f4335e
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBase6.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import static com.android.internal.widget.remotecompose.core.operations.Utils.floatToString;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Base class for draw commands the take 6 floats
+ */
+public abstract class DrawBase6 extends PaintOperation
+ implements VariableSupport {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_RECT) {
+ public Operation construct(float x1, float y1, float x2, float y2) {
+ // return new DrawRectBase(x1, y1, x2, y2);
+ return null;
+ }
+ };
+ protected String mName = "DrawRectBase";
+ float mV1;
+ float mV2;
+ float mV3;
+ float mV4;
+ float mV5;
+ float mV6;
+ float mValue1;
+ float mValue2;
+ float mValue3;
+ float mValue4;
+ float mValue5;
+ float mValue6;
+
+ public DrawBase6(
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ mValue1 = v1;
+ mValue2 = v2;
+ mValue3 = v3;
+ mValue4 = v4;
+ mValue5 = v5;
+ mValue6 = v6;
+
+ mV1 = v1;
+ mV2 = v2;
+ mV3 = v3;
+ mV4 = v4;
+ mV5 = v5;
+ mV6 = v6;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mV1 = (Float.isNaN(mValue1))
+ ? context.getFloat(Utils.idFromNan(mValue1)) : mValue1;
+ mV2 = (Float.isNaN(mValue2))
+ ? context.getFloat(Utils.idFromNan(mValue2)) : mValue2;
+ mV3 = (Float.isNaN(mValue3))
+ ? context.getFloat(Utils.idFromNan(mValue3)) : mValue3;
+ mV4 = (Float.isNaN(mValue4))
+ ? context.getFloat(Utils.idFromNan(mValue4)) : mValue4;
+ mV5 = (Float.isNaN(mValue5))
+ ? context.getFloat(Utils.idFromNan(mValue5)) : mValue5;
+ mV6 = (Float.isNaN(mValue6))
+ ? context.getFloat(Utils.idFromNan(mValue6)) : mValue6;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue1)) {
+ context.listensTo(Utils.idFromNan(mValue1), this);
+ }
+ if (Float.isNaN(mValue2)) {
+ context.listensTo(Utils.idFromNan(mValue2), this);
+ }
+ if (Float.isNaN(mValue3)) {
+ context.listensTo(Utils.idFromNan(mValue3), this);
+ }
+ if (Float.isNaN(mValue4)) {
+ context.listensTo(Utils.idFromNan(mValue4), this);
+ }
+ if (Float.isNaN(mValue5)) {
+ context.listensTo(Utils.idFromNan(mValue5), this);
+ }
+ if (Float.isNaN(mValue6)) {
+ context.listensTo(Utils.idFromNan(mValue6), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mV1, mV2, mV3, mV4, mV5, mV6);
+ }
+
+ @Override
+ public String toString() {
+ return mName + " " + floatToString(mV1) + " " + floatToString(mV2)
+ + " " + floatToString(mV3) + " " + floatToString(mV4);
+ }
+
+ public static class Companion implements CompanionOperation {
+ public final int OP_CODE;
+
+ protected Companion(int code) {
+ OP_CODE = code;
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ float sv1 = buffer.readFloat();
+ float sv2 = buffer.readFloat();
+ float sv3 = buffer.readFloat();
+ float sv4 = buffer.readFloat();
+ float sv5 = buffer.readFloat();
+ float sv6 = buffer.readFloat();
+
+ Operation op = construct(sv1, sv2, sv3, sv4, sv5, sv6);
+ operations.add(op);
+ }
+
+ /**
+ * writes out a the operation to the buffer.
+ * @param v1
+ * @param v2
+ * @param v3
+ * @param v4
+ * @param v5
+ * @param v6
+ * @return
+ */
+ public Operation construct(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ return null;
+ }
+
+ @Override
+ public String name() {
+ return "DrawRect";
+ }
+
+ @Override
+ public int id() {
+ return OP_CODE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param v1
+ * @param v2
+ * @param v3
+ * @param v4
+ * @param v5
+ * @param v6
+ */
+ public void apply(WireBuffer buffer,
+ float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ buffer.start(OP_CODE);
+ buffer.writeFloat(v1);
+ buffer.writeFloat(v2);
+ buffer.writeFloat(v3);
+ buffer.writeFloat(v4);
+ buffer.writeFloat(v5);
+ buffer.writeFloat(v6);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
index 2e971f5..ca40d12 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java
@@ -20,16 +20,22 @@
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import java.util.List;
-public class DrawBitmap extends PaintOperation {
+public class DrawBitmap extends PaintOperation implements VariableSupport {
public static final Companion COMPANION = new Companion();
float mLeft;
float mTop;
float mRight;
float mBottom;
+ float mOutputLeft;
+ float mOutputTop;
+ float mOutputRight;
+ float mOutputBottom;
int mId;
int mDescriptionId = 0;
@@ -49,6 +55,34 @@
}
@Override
+ public void updateVariables(RemoteContext context) {
+ mOutputLeft = (Float.isNaN(mLeft))
+ ? context.getFloat(Utils.idFromNan(mLeft)) : mLeft;
+ mOutputTop = (Float.isNaN(mTop))
+ ? context.getFloat(Utils.idFromNan(mTop)) : mTop;
+ mOutputRight = (Float.isNaN(mRight))
+ ? context.getFloat(Utils.idFromNan(mRight)) : mRight;
+ mOutputBottom = (Float.isNaN(mBottom))
+ ? context.getFloat(Utils.idFromNan(mBottom)) : mBottom;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mLeft)) {
+ context.listensTo(Utils.idFromNan(mLeft), this);
+ }
+ if (Float.isNaN(mTop)) {
+ context.listensTo(Utils.idFromNan(mTop), this);
+ }
+ if (Float.isNaN(mRight)) {
+ context.listensTo(Utils.idFromNan(mRight), this);
+ }
+ if (Float.isNaN(mBottom)) {
+ context.listensTo(Utils.idFromNan(mBottom), this);
+ }
+ }
+
+ @Override
public void write(WireBuffer buffer) {
COMPANION.apply(buffer, mId, mLeft, mTop, mRight, mBottom, mDescriptionId);
}
@@ -105,9 +139,9 @@
@Override
public void paint(PaintContext context) {
- context.drawBitmap(mId, mLeft,
- mTop,
- mRight,
- mBottom);
+ context.drawBitmap(mId, mOutputLeft,
+ mOutputTop,
+ mOutputRight,
+ mOutputBottom);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
index 9ce754d..3a22e4f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java
@@ -1,89 +1,31 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
+public class DrawCircle extends DrawBase3 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_CIRCLE) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2
+ ) {
+ return new DrawCircle(x1, y1, x2);
+ }
+ };
-public class DrawCircle extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mCenterX;
- float mCenterY;
- float mRadius;
-
- public DrawCircle(float centerX, float centerY, float radius) {
- mCenterX = centerX;
- mCenterY = centerY;
- mRadius = radius;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mCenterX,
- mCenterY,
- mRadius);
- }
-
- @Override
- public String toString() {
- return "";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float centerX = buffer.readFloat();
- float centerY = buffer.readFloat();
- float radius = buffer.readFloat();
-
- DrawCircle op = new DrawCircle(centerX, centerY, radius);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "";
- }
-
- @Override
- public int id() {
- return 0;
- }
-
- public void apply(WireBuffer buffer, float centerX, float centerY, float radius) {
- buffer.start(Operations.DRAW_CIRCLE);
- buffer.writeFloat(centerX);
- buffer.writeFloat(centerY);
- buffer.writeFloat(radius);
- }
+ public DrawCircle(
+ float left,
+ float top,
+ float right) {
+ super(left, top, right);
+ mName = "DrawCircle";
}
@Override
public void paint(PaintContext context) {
- context.drawCircle(mCenterX,
- mCenterY,
- mRadius);
+ context.drawCircle(mV1, mV2, mV3);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
index c7a8315..c70c6ea 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java
@@ -15,83 +15,28 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class DrawLine extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mX1;
- float mY1;
- float mX2;
- float mY2;
+public class DrawLine extends DrawBase4 {
+ public static final Companion COMPANION = new Companion(Operations.DRAW_LINE) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new DrawLine(x1, y1, x2, y2);
+ }
+ };
public DrawLine(
- float x1,
- float y1,
- float x2,
- float y2) {
- mX1 = x1;
- mY1 = y1;
- mX2 = x2;
- mY2 = y2;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mX1,
- mY1,
- mX2,
- mY2);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mX1 + " " + mY1
- + " " + mX2 + " " + mY2 + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float x1 = buffer.readFloat();
- float y1 = buffer.readFloat();
- float x2 = buffer.readFloat();
- float y2 = buffer.readFloat();
-
- DrawLine op = new DrawLine(x1, y1, x2, y2);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawLine";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_LINE;
- }
-
- public void apply(WireBuffer buffer,
- float x1,
- float y1,
- float x2,
- float y2) {
- buffer.start(Operations.DRAW_LINE);
- buffer.writeFloat(x1);
- buffer.writeFloat(y1);
- buffer.writeFloat(x2);
- buffer.writeFloat(y2);
- }
+ float left,
+ float top,
+ float right,
+ float bottom) {
+ super(left, top, right, bottom);
+ mName = "DrawLine";
}
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
index 7143753..ba17994 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java
@@ -15,88 +15,33 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class DrawOval extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
-
+public class DrawOval extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_OVAL) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new DrawOval(x1, y1, x2, y2);
+ }
+ };
public DrawOval(
float left,
float top,
float right,
float bottom) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
- }
-
- @Override
- public String toString() {
- return "DrawOval " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
-
- DrawOval op = new DrawOval(sLeft, srcTop, srcRight, srcBottom);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawOval";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_OVAL;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom) {
- buffer.start(Operations.DRAW_OVAL);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- }
+ super(left, top, right, bottom);
+ mName = "DrawOval";
}
@Override
public void paint(PaintContext context) {
- context.drawOval(mLeft,
- mTop,
- mRight,
- mBottom);
+ context.drawOval(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
index 7b8a9e9..6dbc5a6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java
@@ -41,7 +41,7 @@
@Override
public String toString() {
- return "DrawPath " + ";";
+ return "DrawPath " + "[" + mId + "]" + ", " + mStart + ", " + mEnd;
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
index 4775241..633aed4 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java
@@ -15,88 +15,37 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class DrawRect extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
+/**
+ * Draw a Rectangle
+ */
+public class DrawRect extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_RECT) {
+ @Override
+ public Operation construct(float x1,
+ float y1,
+ float x2,
+ float y2) {
+ return new DrawRect(x1, y1, x2, y2);
+ }
+ };
public DrawRect(
float left,
float top,
float right,
float bottom) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom);
- }
-
- @Override
- public String toString() {
- return "DrawRect " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
-
- DrawRect op = new DrawRect(sLeft, srcTop, srcRight, srcBottom);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawRect";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_RECT;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom) {
- buffer.start(Operations.DRAW_RECT);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- }
+ super(left, top, right, bottom);
+ mName = "DrawRect";
}
@Override
public void paint(PaintContext context) {
- context.drawRect(mLeft,
- mTop,
- mRight,
- mBottom);
+ context.drawRect(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
index 8da16e7..b9d0a67 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java
@@ -15,104 +15,40 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
+/**
+ * Draw a rounded rectangle
+ */
+public class DrawRoundRect extends DrawBase6 {
+ public static final Companion COMPANION =
+ new Companion(Operations.DRAW_ROUND_RECT) {
+ @Override
+ public Operation construct(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ return new DrawRoundRect(v1, v2, v3, v4, v5, v6);
+ }
+ };
-public class DrawRoundRect extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mLeft;
- float mTop;
- float mRight;
- float mBottom;
- float mRadiusX;
- float mRadiusY;
-
- public DrawRoundRect(
- float left,
- float top,
- float right,
- float bottom,
- float radiusX,
- float radiusY) {
- mLeft = left;
- mTop = top;
- mRight = right;
- mBottom = bottom;
- mRadiusX = radiusX;
- mRadiusY = radiusY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom, mRadiusX, mRadiusY);
- }
-
- @Override
- public String toString() {
- return "DrawRoundRect " + mLeft + " " + mTop
- + " " + mRight + " " + mBottom
- + " (" + mRadiusX + " " + mRadiusY + ");";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float sLeft = buffer.readFloat();
- float srcTop = buffer.readFloat();
- float srcRight = buffer.readFloat();
- float srcBottom = buffer.readFloat();
- float srcRadiusX = buffer.readFloat();
- float srcRadiusY = buffer.readFloat();
-
- DrawRoundRect op = new DrawRoundRect(sLeft, srcTop, srcRight,
- srcBottom, srcRadiusX, srcRadiusY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "DrawOval";
- }
-
- @Override
- public int id() {
- return Operations.DRAW_ROUND_RECT;
- }
-
- public void apply(WireBuffer buffer,
- float left,
- float top,
- float right,
- float bottom,
- float radiusX,
- float radiusY) {
- buffer.start(Operations.DRAW_ROUND_RECT);
- buffer.writeFloat(left);
- buffer.writeFloat(top);
- buffer.writeFloat(right);
- buffer.writeFloat(bottom);
- buffer.writeFloat(radiusX);
- buffer.writeFloat(radiusY);
- }
+ public DrawRoundRect(float v1,
+ float v2,
+ float v3,
+ float v4,
+ float v5,
+ float v6) {
+ super(v1, v2, v3, v4, v5, v6);
+ mName = "ClipRect";
}
@Override
public void paint(PaintContext context) {
- context.drawRoundRect(mLeft,
- mTop,
- mRight,
- mBottom,
- mRadiusX,
- mRadiusY
+ context.drawRoundRect(mV1, mV2, mV3, mV4, mV5, mV6
);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
new file mode 100644
index 0000000..f8f8afd
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawText.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Draw Text
+ */
+public class DrawText extends PaintOperation {
+ public static final Companion COMPANION = new Companion();
+ int mTextID;
+ int mStart = 0;
+ int mEnd = 0;
+ int mContextStart = 0;
+ int mContextEnd = 0;
+ float mX = 0f;
+ float mY = 0f;
+ boolean mRtl = false;
+
+ public DrawText(int textID,
+ int start,
+ int end,
+ int contextStart,
+ int contextEnd,
+ float x,
+ float y,
+ boolean rtl) {
+ mTextID = textID;
+ mStart = start;
+ mEnd = end;
+ mContextStart = contextStart;
+ mContextEnd = contextEnd;
+ mX = x;
+ mY = y;
+ mRtl = rtl;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl);
+
+ }
+
+ @Override
+ public String toString() {
+ return "DrawTextRun [" + mTextID + "] " + mStart + ", " + mEnd + ", " + mX + ", " + mY;
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int text = buffer.readInt();
+ int start = buffer.readInt();
+ int end = buffer.readInt();
+ int contextStart = buffer.readInt();
+ int contextEnd = buffer.readInt();
+ float x = buffer.readFloat();
+ float y = buffer.readFloat();
+ boolean rtl = buffer.readBoolean();
+ DrawText op = new DrawText(text, start, end, contextStart, contextEnd, x, y, rtl);
+
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "";
+ }
+
+ @Override
+ public int id() {
+ return 0;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textID
+ * @param start
+ * @param end
+ * @param contextStart
+ * @param contextEnd
+ * @param x
+ * @param y
+ * @param rtl
+ */
+ public void apply(WireBuffer buffer,
+ int textID,
+ int start,
+ int end,
+ int contextStart,
+ int contextEnd,
+ float x,
+ float y,
+ boolean rtl) {
+ buffer.start(Operations.DRAW_TEXT_RUN);
+ buffer.writeInt(textID);
+ buffer.writeInt(start);
+ buffer.writeInt(end);
+ buffer.writeInt(contextStart);
+ buffer.writeInt(contextEnd);
+ buffer.writeFloat(x);
+ buffer.writeFloat(y);
+ buffer.writeBoolean(rtl);
+ }
+ }
+
+ @Override
+ public void paint(PaintContext context) {
+ context.drawTextRun(mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
new file mode 100644
index 0000000..4f0641f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextAnchored.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Draw Text in Anchored to a point
+ */
+public class DrawTextAnchored extends PaintOperation implements VariableSupport {
+ public static final Companion COMPANION = new Companion();
+ int mTextID;
+ float mX;
+ float mY;
+ float mPanX;
+ float mPanY;
+ int mFlags;
+ float mOutX;
+ float mOutY;
+ float mOutPanX;
+ float mOutPanY;
+
+ public static final int ANCHOR_TEXT_RTL = 1;
+ public static final int ANCHOR_MONOSPACE_MEASURE = 2;
+
+ public DrawTextAnchored(int textID,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+ mTextID = textID;
+ mX = x;
+ mY = y;
+ mOutX = mX;
+ mOutY = mY;
+ mFlags = flags;
+ mOutPanX = mPanX = panX;
+ mOutPanY = mPanY = panY;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ mOutX = (Float.isNaN(mX))
+ ? context.getFloat(Utils.idFromNan(mX)) : mX;
+ mOutY = (Float.isNaN(mY))
+ ? context.getFloat(Utils.idFromNan(mY)) : mY;
+ mOutPanX = (Float.isNaN(mPanX))
+ ? context.getFloat(Utils.idFromNan(mPanX)) : mPanX;
+ mOutPanY = (Float.isNaN(mPanY))
+ ? context.getFloat(Utils.idFromNan(mPanY)) : mPanY;
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mX)) {
+ context.listensTo(Utils.idFromNan(mX), this);
+ }
+ if (Float.isNaN(mY)) {
+ context.listensTo(Utils.idFromNan(mY), this);
+ }
+ if (Float.isNaN(mPanX)) {
+ context.listensTo(Utils.idFromNan(mPanX), this);
+ }
+ if (Float.isNaN(mPanY) && Utils.idFromNan(mPanY) > 0) {
+ context.listensTo(Utils.idFromNan(mPanY), this);
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextID, mX,
+ mY,
+ mPanX,
+ mPanY,
+ mFlags);
+ }
+
+ @Override
+ public String toString() {
+ return "DrawTextAnchored [" + mTextID + "] " + floatToStr(mX) + ", "
+ + floatToStr(mY) + ", "
+ + floatToStr(mPanX) + ", " + floatToStr(mPanY) + ", "
+ + Integer.toBinaryString(mFlags);
+ }
+
+ private static String floatToStr(float v) {
+ if (Float.isNaN(v)) {
+ return "[" + Utils.idFromNan(v) + "]";
+ }
+ return Float.toString(v);
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textID = buffer.readInt();
+ float x = buffer.readFloat();
+ float y = buffer.readFloat();
+ float panX = buffer.readFloat();
+ float panY = buffer.readFloat();
+ int flags = buffer.readInt();
+
+ DrawTextAnchored op = new DrawTextAnchored(textID,
+ x, y,
+ panX, panY,
+ flags);
+
+ operations.add(op);
+ }
+
+ @Override
+ public String name() {
+ return "";
+ }
+
+ @Override
+ public int id() {
+ return 0;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textID
+ * @param x
+ * @param y
+ * @param panX
+ * @param panY
+ * @param flags
+ */
+ public void apply(WireBuffer buffer,
+ int textID,
+ float x,
+ float y,
+ float panX,
+ float panY,
+ int flags) {
+ buffer.start(Operations.DRAW_TEXT_ANCHOR);
+ buffer.writeInt(textID);
+ buffer.writeFloat(x);
+ buffer.writeFloat(y);
+ buffer.writeFloat(panX);
+ buffer.writeFloat(panY);
+ buffer.writeInt(flags);
+ }
+ }
+
+ float[] mBounds = new float[4];
+
+ private float getHorizontalOffset() {
+ // TODO scale TextSize / BaseTextSize;
+ float scale = 1.0f;
+
+ float textWidth = scale * (mBounds[2] - mBounds[0]);
+ float boxWidth = 0;
+ return (boxWidth - textWidth) * (1 + mOutPanX) / 2.f
+ - (scale * mBounds[0]);
+ }
+
+ private float getVerticalOffset() {
+ // TODO scale TextSize / BaseTextSize;
+ float scale = 1.0f;
+ float boxHeight = 0;
+ float textHeight = scale * (mBounds[3] - mBounds[1]);
+ return (boxHeight - textHeight) * (1 - mOutPanY) / 2
+ - (scale * mBounds[1]);
+ }
+
+ @Override
+ public void paint(PaintContext context) {
+ context.getTextBounds(mTextID, 0, -1,
+ (mFlags & ANCHOR_MONOSPACE_MEASURE) != 0, mBounds);
+ float x = mOutX + getHorizontalOffset();
+ float y = (Float.isNaN(mOutPanY)) ? mOutY : mOutY + getVerticalOffset();
+ context.drawTextRun(mTextID, 0, -1, 0, 1, x, y,
+ (mFlags & ANCHOR_TEXT_RTL) == 1);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
index 1856e30..b1a0172 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java
@@ -24,6 +24,9 @@
import java.util.List;
+/**
+ * Draw text along a path.
+ */
public class DrawTextOnPath extends PaintOperation {
public static final Companion COMPANION = new Companion();
int mPathId;
@@ -45,7 +48,8 @@
@Override
public String toString() {
- return "DrawTextOnPath " + " " + mPathId + ";";
+ return "DrawTextOnPath [" + mTextId + "] [" + mPathId + "] "
+ + mHOffset + ", " + mVOffset;
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
index ef0a4ad..48fc94e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java
@@ -58,7 +58,7 @@
public String toString() {
return "DrawTweenPath " + mPath1Id + " " + mPath2Id
+ " " + mTween + " " + mStart + " "
- + "- " + mStop + ";";
+ + "- " + mStop;
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
new file mode 100644
index 0000000..576b53f
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatConstant.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to deal with Text data
+ */
+public class FloatConstant implements Operation {
+ public int mTextId;
+ public float mValue;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public FloatConstant(int textId, float value) {
+ this.mTextId = textId;
+ this.mValue = value;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextId, mValue);
+ }
+
+ @Override
+ public String toString() {
+ return "FloatConstant[" + mTextId + "] = " + mValue + "";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {}
+
+ @Override
+ public String name() {
+ return "FloatExpression";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DATA_FLOAT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textId
+ * @param value
+ */
+ public void apply(WireBuffer buffer, int textId, float value) {
+ buffer.start(Operations.DATA_FLOAT);
+ buffer.writeInt(textId);
+ buffer.writeFloat(value);
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textId = buffer.readInt();
+
+ float value = buffer.readFloat();
+ operations.add(new FloatConstant(textId, value));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ context.loadFloat(mTextId, mValue);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
new file mode 100644
index 0000000..354f41b
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/FloatExpression.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.operations.utilities.AnimatedFloatExpression;
+import com.android.internal.widget.remotecompose.core.operations.utilities.easing.FloatAnimation;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Operation to deal with AnimatedFloats
+ * This is designed to be an optimized calculation for things like
+ * injecting the width of the component int draw rect
+ * As well as supporting generalized animation floats.
+ * The floats represent a RPN style calculator
+ */
+public class FloatExpression implements Operation, VariableSupport {
+ public int mId;
+ public float[] mSrcValue;
+ public float[] mSrcAnimation;
+ public FloatAnimation mFloatAnimation;
+ public float[] mPreCalcValue;
+ private float mLastChange = Float.NaN;
+ AnimatedFloatExpression mExp = new AnimatedFloatExpression();
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public FloatExpression(int id, float[] value, float[] animation) {
+ this.mId = id;
+ this.mSrcValue = value;
+ this.mSrcAnimation = animation;
+ if (mSrcAnimation != null) {
+ mFloatAnimation = new FloatAnimation(mSrcAnimation);
+ }
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ if (mPreCalcValue == null || mPreCalcValue.length != mSrcValue.length) {
+ mPreCalcValue = new float[mSrcValue.length];
+ }
+ //Utils.log("updateVariables ");
+ boolean value_changed = false;
+ for (int i = 0; i < mSrcValue.length; i++) {
+ float v = mSrcValue[i];
+ if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v)) {
+ float newValue = context.getFloat(Utils.idFromNan(v));
+ if (mFloatAnimation != null) {
+ if (mPreCalcValue[i] != newValue) {
+ mLastChange = context.getAnimationTime();
+ value_changed = true;
+ mPreCalcValue[i] = newValue;
+ }
+ } else {
+ mPreCalcValue[i] = newValue;
+ }
+ } else {
+ mPreCalcValue[i] = mSrcValue[i];
+ }
+ }
+ if (value_changed && mFloatAnimation != null) {
+ float v = mExp.eval(Arrays.copyOf(mPreCalcValue, mPreCalcValue.length));
+ if (Float.isNaN(mFloatAnimation.getTargetValue())) {
+ mFloatAnimation.setInitialValue(v);
+ } else {
+ mFloatAnimation.setInitialValue(mFloatAnimation.getTargetValue());
+ }
+ mFloatAnimation.setTargetValue(v);
+ }
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ for (int i = 0; i < mSrcValue.length; i++) {
+ float v = mSrcValue[i];
+ if (Float.isNaN(v) && !AnimatedFloatExpression.isMathOperator(v)) {
+ context.listensTo(Utils.idFromNan(v), this);
+ }
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ updateVariables(context);
+ float t = context.getAnimationTime();
+ if (Float.isNaN(mLastChange)) {
+ mLastChange = t;
+ }
+ if (mFloatAnimation != null) {
+ float f = mFloatAnimation.get(t - mLastChange);
+ context.loadFloat(mId, f);
+ } else {
+ context.loadFloat(mId, mExp.eval(Arrays.copyOf(mPreCalcValue, mPreCalcValue.length)));
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mId, mSrcValue, mSrcAnimation);
+ }
+
+ @Override
+ public String toString() {
+ String[] labels = new String[mSrcValue.length];
+ for (int i = 0; i < mSrcValue.length; i++) {
+ if (Float.isNaN(mSrcValue[i])) {
+ labels[i] = "[" + Utils.idFromNan(mSrcValue[i]) + "]";
+ }
+
+ }
+ return "FloatExpression[" + mId + "] = ("
+ + AnimatedFloatExpression.toString(mPreCalcValue, labels) + ")";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "FloatExpression";
+ }
+
+ @Override
+ public int id() {
+ return Operations.ANIMATED_FLOAT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param id
+ * @param value
+ * @param animation
+ */
+ public void apply(WireBuffer buffer, int id, float[] value, float[] animation) {
+ buffer.start(Operations.ANIMATED_FLOAT);
+ buffer.writeInt(id);
+
+ int len = value.length;
+ if (animation != null) {
+ len |= (animation.length << 16);
+ }
+ buffer.writeInt(len);
+
+ for (int i = 0; i < value.length; i++) {
+ buffer.writeFloat(value[i]);
+ }
+ if (animation != null) {
+ for (int i = 0; i < animation.length; i++) {
+ buffer.writeFloat(animation[i]);
+ }
+ }
+
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int id = buffer.readInt();
+ int len = buffer.readInt();
+ int valueLen = len & 0xFFFF;
+ int animLen = (len >> 16) & 0xFFFF;
+ float[] values = new float[valueLen];
+ for (int i = 0; i < values.length; i++) {
+ values[i] = buffer.readFloat();
+ }
+
+ float[] animation;
+ if (animLen != 0) {
+ animation = new float[animLen];
+ for (int i = 0; i < animation.length; i++) {
+ animation[i] = buffer.readFloat();
+ }
+ } else {
+ animation = null;
+ }
+ operations.add(new FloatExpression(id, values, animation));
+ }
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
index 482e0e2..0dad45c 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java
@@ -37,7 +37,7 @@
@Override
public String toString() {
- return "MatrixRestore;";
+ return "MatrixRestore";
}
public static class Companion implements CompanionOperation {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
index d6c89e0..bbf4135 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java
@@ -15,68 +15,29 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class MatrixRotate extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mRotate, mPivotX, mPivotY;
+public class MatrixRotate extends DrawBase3 {
+ public static final Companion COMPANION =
+ new Companion(Operations.MATRIX_ROTATE) {
+ @Override
+ public Operation construct(float rotate,
+ float pivotX,
+ float pivotY
+ ) {
+ return new MatrixRotate(rotate, pivotX, pivotY);
+ }
+ };
public MatrixRotate(float rotate, float pivotX, float pivotY) {
- mRotate = rotate;
- mPivotX = pivotX;
- mPivotY = pivotY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mRotate, mPivotX, mPivotY);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mRotate + ", " + mPivotX + ", " + mPivotY + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float rotate = buffer.readFloat();
- float pivotX = buffer.readFloat();
- float pivotY = buffer.readFloat();
- MatrixRotate op = new MatrixRotate(rotate, pivotX, pivotY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "Matrix";
- }
-
- @Override
- public int id() {
- return Operations.MATRIX_ROTATE;
- }
-
- public void apply(WireBuffer buffer, float rotate, float pivotX, float pivotY) {
- buffer.start(Operations.MATRIX_ROTATE);
- buffer.writeFloat(rotate);
- buffer.writeFloat(pivotX);
- buffer.writeFloat(pivotY);
- }
+ super(rotate, pivotX, pivotY);
+ mName = "MatrixRotate";
}
@Override
public void paint(PaintContext context) {
- context.matrixRotate(mRotate, mPivotX, mPivotY);
+ context.matrixRotate(mV1, mV2, mV3);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
index 28aa68dd..04b940b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java
@@ -15,74 +15,30 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class MatrixScale extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mScaleX, mScaleY;
- float mCenterX, mCenterY;
+public class MatrixScale extends DrawBase4 {
+ public static final Companion COMPANION =
+ new Companion(Operations.MATRIX_SCALE) {
+ @Override
+ public Operation construct(float scaleX,
+ float scaleY,
+ float centerX,
+ float centerY
+ ) {
+ return new MatrixScale(scaleX, scaleY, centerX, centerY);
+ }
+ };
public MatrixScale(float scaleX, float scaleY, float centerX, float centerY) {
- mScaleX = scaleX;
- mScaleY = scaleY;
- mCenterX = centerX;
- mCenterY = centerY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mScaleX, mScaleY, mCenterX, mCenterY);
- }
-
- @Override
- public String toString() {
- return "MatrixScale " + mScaleY + ", " + mScaleY + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float scaleX = buffer.readFloat();
- float scaleY = buffer.readFloat();
- float centerX = buffer.readFloat();
- float centerY = buffer.readFloat();
- MatrixScale op = new MatrixScale(scaleX, scaleY, centerX, centerY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "Matrix";
- }
-
- @Override
- public int id() {
- return Operations.MATRIX_SCALE;
- }
-
- public void apply(WireBuffer buffer, float scaleX, float scaleY,
- float centerX, float centerY) {
- buffer.start(Operations.MATRIX_SCALE);
- buffer.writeFloat(scaleX);
- buffer.writeFloat(scaleY);
- buffer.writeFloat(centerX);
- buffer.writeFloat(centerY);
-
- }
+ super(scaleX, scaleY, centerX, centerY);
+ mName = "MatrixScale";
}
@Override
public void paint(PaintContext context) {
- context.mtrixScale(mScaleX, mScaleY, mCenterX, mCenterY);
+ context.matrixScale(mX1, mY1, mX2, mY2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
index 3298752..4f34e98 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java
@@ -15,65 +15,28 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
-import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
-import com.android.internal.widget.remotecompose.core.PaintOperation;
-import com.android.internal.widget.remotecompose.core.WireBuffer;
-import java.util.List;
-
-public class MatrixTranslate extends PaintOperation {
- public static final Companion COMPANION = new Companion();
- float mTranslateX, mTranslateY;
+public class MatrixTranslate extends DrawBase2 {
+ public static final Companion COMPANION =
+ new Companion(Operations.MATRIX_TRANSLATE) {
+ @Override
+ public Operation construct(float x1,
+ float y1
+ ) {
+ return new MatrixTranslate(x1, y1);
+ }
+ };
public MatrixTranslate(float translateX, float translateY) {
- mTranslateX = translateX;
- mTranslateY = translateY;
- }
-
- @Override
- public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mTranslateX, mTranslateY);
- }
-
- @Override
- public String toString() {
- return "DrawArc " + mTranslateY + ", " + mTranslateY + ";";
- }
-
- public static class Companion implements CompanionOperation {
- private Companion() {
- }
-
- @Override
- public void read(WireBuffer buffer, List<Operation> operations) {
- float translateX = buffer.readFloat();
- float translateY = buffer.readFloat();
- MatrixTranslate op = new MatrixTranslate(translateX, translateY);
- operations.add(op);
- }
-
- @Override
- public String name() {
- return "Matrix";
- }
-
- @Override
- public int id() {
- return Operations.MATRIX_TRANSLATE;
- }
-
- public void apply(WireBuffer buffer, float translateX, float translateY) {
- buffer.start(Operations.MATRIX_TRANSLATE);
- buffer.writeFloat(translateX);
- buffer.writeFloat(translateY);
- }
+ super(translateX, translateY);
+ mName = "MatrixTranslate";
}
@Override
public void paint(PaintContext context) {
- context.matrixTranslate(mTranslateX, mTranslateY);
+ context.matrixTranslate(mV1, mV2);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
new file mode 100644
index 0000000..0c5b286
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/NamedVariable.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to deal with Text data
+ */
+public class NamedVariable implements Operation {
+ public int mVarId;
+ public String mVarName;
+ public int mVarType;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public NamedVariable(int varId, int varType, String name) {
+ this.mVarId = varId;
+ this.mVarType = varType;
+ this.mVarName = name;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mVarId, mVarType, mVarName);
+ }
+
+ @Override
+ public String toString() {
+ return "VariableName[" + mVarId + "] = \""
+ + Utils.trimString(mVarName, 10) + "\" type=" + mVarType;
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "TextData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DATA_TEXT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param varId
+ * @param varType
+ * @param text
+ */
+ public void apply(WireBuffer buffer, int varId, int varType, String text) {
+ buffer.start(Operations.DATA_TEXT);
+ buffer.writeInt(varId);
+ buffer.writeInt(varType);
+ buffer.writeUTF8(text);
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int varId = buffer.readInt();
+ int varType = buffer.readInt();
+ String text = buffer.readUTF8(MAX_STRING_SIZE);
+ operations.add(new NamedVariable(varId, varType, text));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ context.loadVariableName(mVarName, mVarId, mVarType);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
index e5683ec..0807bcd 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java
@@ -20,12 +20,14 @@
import com.android.internal.widget.remotecompose.core.Operations;
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.PaintOperation;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import java.util.List;
-public class PaintData extends PaintOperation {
+public class PaintData extends PaintOperation implements VariableSupport {
public PaintBundle mPaintData = new PaintBundle();
public static final Companion COMPANION = new Companion();
public static final int MAX_STRING_SIZE = 4000;
@@ -34,6 +36,16 @@
}
@Override
+ public void updateVariables(RemoteContext context) {
+ mPaintData.updateVariables(context);
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ mPaintData.registerVars(context, this);
+ }
+
+ @Override
public void write(WireBuffer buffer) {
COMPANION.apply(buffer, mPaintData);
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
index 2646b27..e467e7b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java
@@ -18,27 +18,50 @@
import com.android.internal.widget.remotecompose.core.CompanionOperation;
import com.android.internal.widget.remotecompose.core.Operation;
import com.android.internal.widget.remotecompose.core.Operations;
-import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
+import java.util.Arrays;
import java.util.List;
-public class PathData implements Operation {
+public class PathData implements Operation, VariableSupport {
public static final Companion COMPANION = new Companion();
int mInstanceId;
- float[] mRef;
float[] mFloatPath;
- float[] mRetFloats;
+ float[] mOutputPath;
PathData(int instanceId, float[] floatPath) {
mInstanceId = instanceId;
mFloatPath = floatPath;
+ mOutputPath = Arrays.copyOf(mFloatPath, mFloatPath.length);
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ for (int i = 0; i < mFloatPath.length; i++) {
+ float v = mFloatPath[i];
+ if (Utils.isVariable(v)) {
+ mOutputPath[i] = (Float.isNaN(v))
+ ? context.getFloat(Utils.idFromNan(v)) : v;
+ } else {
+ mOutputPath[i] = v;
+ }
+ }
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ for (int i = 0; i < mFloatPath.length; i++) {
+ if (Float.isNaN(mFloatPath[i])) {
+ context.listensTo(Utils.idFromNan(mFloatPath[i]), this);
+ }
+ }
}
@Override
public void write(WireBuffer buffer) {
- COMPANION.apply(buffer, mInstanceId, mFloatPath);
+ COMPANION.apply(buffer, mInstanceId, mOutputPath);
}
@Override
@@ -46,29 +69,35 @@
return pathString(mFloatPath);
}
- public float[] getFloatPath(PaintContext context) {
- float[] ret = mRetFloats; // Assume retFloats is declared elsewhere
- if (ret == null) {
- return mFloatPath; // Assume floatPath is declared elsewhere
- }
- float[] localRef = mRef; // Assume ref is of type Float[]
- if (localRef == null) {
- for (int i = 0; i < mFloatPath.length; i++) {
- ret[i] = mFloatPath[i];
- }
- } else {
- for (int i = 0; i < mFloatPath.length; i++) {
- float lr = localRef[i];
- if (Float.isNaN(lr)) {
- ret[i] = Utils.getActualValue(lr);
- } else {
- ret[i] = mFloatPath[i];
- }
- }
- }
- return ret;
+ @Override
+ public String toString() {
+ return "PathData[" + mInstanceId + "] = " + "\"" + deepToString(" ") + "\"";
}
+ /**
+ * public float[] getFloatPath(PaintContext context) {
+ * float[] ret = mRetFloats; // Assume retFloats is declared elsewhere
+ * if (ret == null) {
+ * return mFloatPath; // Assume floatPath is declared elsewhere
+ * }
+ * float[] localRef = mRef; // Assume ref is of type Float[]
+ * if (localRef == null) {
+ * for (int i = 0; i < mFloatPath.length; i++) {
+ * ret[i] = mFloatPath[i];
+ * }
+ * } else {
+ * for (int i = 0; i < mFloatPath.length; i++) {
+ * float lr = localRef[i];
+ * if (Float.isNaN(lr)) {
+ * ret[i] = Utils.getActualValue(lr);
+ * } else {
+ * ret[i] = mFloatPath[i];
+ * }
+ * }
+ * }
+ * return ret;
+ * }
+ */
public static final int MOVE = 10;
public static final int LINE = 11;
public static final int QUADRATIC = 12;
@@ -155,7 +184,7 @@
str.append(".");
break;
default:
- str.append("X");
+ str.append("[" + id + "]");
break;
}
} else {
@@ -170,7 +199,7 @@
@Override
public void apply(RemoteContext context) {
- context.loadPathData(mInstanceId, mFloatPath);
+ context.loadPathData(mInstanceId, mOutputPath);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
index 6d924eb..997e8dc 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java
@@ -94,7 +94,6 @@
public static final int SCALE_CROP = 5;
public static final int SCALE_FILL_BOUNDS = 6;
-
public static final Companion COMPANION = new Companion();
/**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
index 64c7f3e..076b28e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentDescription.java
@@ -48,7 +48,7 @@
@Override
public String toString() {
- return "ROOT_CONTENT_DESCRIPTION " + mContentDescription;
+ return "RootContentDescription " + mContentDescription;
}
@Override
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
new file mode 100644
index 0000000..8463ac5
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Operation to deal with bitmap data
+ * On getting an Image during a draw call the bitmap is compressed and saved
+ * in playback the image is decompressed
+ */
+public class ShaderData implements Operation, VariableSupport {
+ int mShaderTextId; // the actual text of a shader
+ int mShaderID; // allows shaders to be referenced by number
+ HashMap<String, float[]> mUniformRawFloatMap = null;
+ HashMap<String, float[]> mUniformFloatMap = null;
+ HashMap<String, int[]> mUniformIntMap = null;
+ HashMap<String, Integer> mUniformBitmapMap = null;
+
+ public static final int MAX_IMAGE_DIMENSION = 8000;
+
+ public static final Companion COMPANION = new Companion();
+
+ public ShaderData(int shaderID,
+ int shaderTextId,
+ HashMap<String, float[]> floatMap,
+ HashMap<String, int[]> intMap,
+ HashMap<String, Integer> bitmapMap) {
+ mShaderID = shaderID;
+ mShaderTextId = shaderTextId;
+ if (floatMap != null) {
+ mUniformFloatMap = new HashMap<>();
+ mUniformRawFloatMap = new HashMap<>();
+
+ for (String name : floatMap.keySet()) {
+ mUniformRawFloatMap.put(name, floatMap.get(name));
+ mUniformFloatMap.put(name, floatMap.get(name));
+ }
+ }
+
+ if (intMap != null) {
+ mUniformIntMap = new HashMap<>();
+ for (String name : intMap.keySet()) {
+ mUniformIntMap.put(name, intMap.get(name));
+ }
+ }
+ if (bitmapMap != null) {
+ mUniformBitmapMap = new HashMap<>();
+ for (String name : bitmapMap.keySet()) {
+ mUniformBitmapMap.put(name, bitmapMap.get(name));
+ }
+ }
+
+ }
+
+ public int getShaderTextId() {
+ return mShaderTextId;
+ }
+
+ /**
+ * get names of all known floats
+ * @return
+ */
+ public String[] getUniformFloatNames() {
+ if (mUniformFloatMap == null) return new String[0];
+ return mUniformFloatMap.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * Get float values associated with the name
+ * @param name
+ * @return
+ */
+ public float[] getUniformFloats(String name) {
+ return mUniformFloatMap.get(name);
+ }
+
+ /**
+ * get the name of all know uniform integers
+ * @return
+ */
+ public String[] getUniformIntegerNames() {
+ if (mUniformIntMap == null) return new String[0];
+ return mUniformIntMap.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * Get Int value associated with the name
+ * @param name
+ * @return
+ */
+ public int[] getUniformInts(String name) {
+ return mUniformIntMap.get(name);
+ }
+
+ /**
+ * get list of uniform Bitmaps
+ * @return
+ */
+ public String[] getUniformBitmapNames() {
+ if (mUniformBitmapMap == null) return new String[0];
+ return mUniformBitmapMap.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * Get a bitmap stored under that name
+ * @param name
+ * @return
+ */
+ public int getUniformBitmapId(String name) {
+ return mUniformBitmapMap.get(name);
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mShaderID, mShaderTextId,
+ mUniformFloatMap, mUniformIntMap, mUniformBitmapMap);
+ }
+
+ @Override
+ public String toString() {
+ return "SHADER DATA " + mShaderID;
+ }
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ for (String name : mUniformRawFloatMap.keySet()) {
+ float[] value = mUniformRawFloatMap.get(name);
+ float[] out = null;
+ for (int i = 0; i < value.length; i++) {
+ if (Float.isNaN(value[i])) {
+ if (out == null) { // need to copy
+ out = Arrays.copyOf(value, value.length);
+ }
+ out[i] = context.getFloat(Utils.idFromNan(value[i]));
+ }
+ }
+ mUniformFloatMap.put(name, out == null ? value : out);
+ }
+ }
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ for (String name : mUniformRawFloatMap.keySet()) {
+ float[] value = mUniformRawFloatMap.get(name);
+ for (int i = 0; i < value.length; i++) {
+ if (Float.isNaN(value[i])) {
+ context.listensTo(Utils.idFromNan(value[i]), this);
+ }
+ }
+ }
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "BitmapData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.DATA_SHADER;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param shaderID
+ * @param shaderTextId
+ * @param floatMap
+ * @param intMap
+ * @param bitmapMap
+ */
+ public void apply(WireBuffer buffer, int shaderID, int shaderTextId,
+ HashMap<String, float[]> floatMap,
+ HashMap<String, int[]> intMap,
+ HashMap<String, Integer> bitmapMap) {
+ buffer.start(Operations.DATA_SHADER);
+ buffer.writeInt(shaderID);
+
+ buffer.writeInt(shaderTextId);
+ int floatSize = (floatMap == null) ? 0 : floatMap.size();
+ int intSize = (intMap == null) ? 0 : intMap.size();
+ int bitmapSize = (bitmapMap == null) ? 0 : bitmapMap.size();
+ int sizes = floatSize | (intSize << 8) | (bitmapSize << 16);
+ buffer.writeInt(sizes);
+
+ if (floatSize > 0) {
+
+ for (String name : floatMap.keySet()) {
+ buffer.writeUTF8(name);
+ float[] values = floatMap.get(name);
+ buffer.writeInt(values.length);
+
+ for (int i = 0; i < values.length; i++) {
+ buffer.writeFloat(values[i]);
+ }
+ }
+ }
+
+ if (intSize > 0) {
+ for (String name : intMap.keySet()) {
+ buffer.writeUTF8(name);
+ int[] values = intMap.get(name);
+ buffer.writeInt(values.length);
+ for (int i = 0; i < values.length; i++) {
+ buffer.writeInt(values[i]);
+ }
+ }
+ }
+ if (bitmapSize > 0) {
+ for (String name : bitmapMap.keySet()) {
+ buffer.writeUTF8(name);
+ int value = bitmapMap.get(name);
+ buffer.writeInt(value);
+ }
+ }
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int shaderID = buffer.readInt();
+ int shaderTextId = buffer.readInt();
+ HashMap<String, float[]> floatMap = null;
+ HashMap<String, int[]> intMap = null;
+ HashMap<String, Integer> bitmapMap = null;
+
+ int sizes = buffer.readInt();
+
+ int floatMapSize = sizes & 0xFF;
+ if (floatMapSize > 0) {
+ floatMap = new HashMap<>();
+ for (int i = 0; i < floatMapSize; i++) {
+ String name = buffer.readUTF8();
+ int len = buffer.readInt();
+ float[] val = new float[len];
+
+ for (int j = 0; j < len; j++) {
+ val[j] = buffer.readFloat();
+ }
+
+ floatMap.put(name, val);
+ }
+ }
+ int intMapSize = (sizes >> 8) & 0xFF;
+
+ if (intMapSize > 0) {
+
+ intMap = new HashMap<>();
+ for (int i = 0; i < intMapSize; i++) {
+ String name = buffer.readUTF8();
+ int len = buffer.readInt();
+ int[] val = new int[len];
+ for (int j = 0; j < len; j++) {
+ val[j] = buffer.readInt();
+ }
+ intMap.put(name, val);
+ }
+ }
+ int bitmapMapSize = (sizes >> 16) & 0xFF;
+
+ if (bitmapMapSize > 0) {
+ bitmapMap = new HashMap<>();
+ for (int i = 0; i < bitmapMapSize; i++) {
+ String name = buffer.readUTF8();
+ int val = buffer.readInt();
+ bitmapMap.put(name, val);
+ }
+ }
+ operations.add(new ShaderData(shaderID, shaderTextId,
+ floatMap, intMap, bitmapMap));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ context.loadShader(mShaderID, this);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
index 5b622ae..ed13449 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextData.java
@@ -44,11 +44,13 @@
@Override
public String toString() {
- return "TEXT DATA " + mTextId + "\"" + mText + "\"";
+ return "TextData[" + mTextId + "] = \""
+ + Utils.trimString(mText, 10) + "\"";
}
public static class Companion implements CompanionOperation {
- private Companion() {}
+ private Companion() {
+ }
@Override
public String name() {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
new file mode 100644
index 0000000..65a39a1e
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextFromFloat.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.operations.utilities.StringUtils;
+
+import java.util.List;
+
+/**
+ * Operation convert floats to text
+ * This command is structured [command][textID][before,after][flags]
+ * before and after define number of digits before and after the decimal point
+ */
+public class TextFromFloat implements Operation, VariableSupport {
+ public int mTextId;
+ public float mValue;
+ public float mOutValue;
+ public short mDigitsBefore;
+ public short mDigitsAfter;
+ public int mFlags;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+ char mPre = ' ';
+ char mAfter = ' ';
+ // Theses flags define what how to/if fill the space
+ public static final int PAD_AFTER_SPACE = 0; // pad past point with space
+ public static final int PAD_AFTER_NONE = 1; // do not pad past last digit
+ public static final int PAD_AFTER_ZERO = 3; // pad with 0 past last digit
+ public static final int PAD_PRE_SPACE = 0; // pad before number with spaces
+ public static final int PAD_PRE_NONE = 4; // pad before number with 0s
+ public static final int PAD_PRE_ZERO = 12; // do not pad before number
+
+ public TextFromFloat(int textId, float value, short digitsBefore,
+ short digitsAfter, int flags) {
+ this.mTextId = textId;
+ this.mValue = value;
+ this.mDigitsAfter = digitsAfter;
+ this.mDigitsBefore = digitsBefore;
+ this.mFlags = flags;
+ mOutValue = mValue;
+ switch (mFlags & 3) {
+ case PAD_AFTER_SPACE:
+ mAfter = ' ';
+ break;
+ case PAD_AFTER_NONE:
+ mAfter = 0;
+ break;
+ case PAD_AFTER_ZERO:
+ mAfter = '0';
+ break;
+ }
+ switch (mFlags & 12) {
+ case PAD_PRE_SPACE:
+ mPre = ' ';
+ break;
+ case PAD_PRE_NONE:
+ mPre = 0;
+ break;
+ case PAD_PRE_ZERO:
+ mPre = '0';
+ break;
+ }
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextId, mValue, mDigitsAfter, mDigitsBefore, mFlags);
+ }
+
+ @Override
+ public String toString() {
+ return "TextFromFloat[" + mTextId + "] = "
+ + Utils.floatToString(mValue) + " " + mDigitsBefore
+ + "." + mDigitsAfter + " " + mFlags;
+ }
+
+
+ @Override
+ public void updateVariables(RemoteContext context) {
+ if (Float.isNaN(mValue)) {
+ mOutValue = context.getFloat(Utils.idFromNan(mValue));
+ }
+
+ }
+
+
+ @Override
+ public void registerListening(RemoteContext context) {
+ if (Float.isNaN(mValue)) {
+ context.listensTo(Utils.idFromNan(mValue), this);
+ }
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "TextData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.TEXT_FROM_FLOAT;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textId
+ * @param value
+ * @param digitsBefore
+ * @param digitsAfter
+ * @param flags
+ */
+ public void apply(WireBuffer buffer, int textId,
+ float value, short digitsBefore,
+ short digitsAfter, int flags) {
+ buffer.start(Operations.TEXT_FROM_FLOAT);
+ buffer.writeInt(textId);
+ buffer.writeFloat(value);
+ buffer.writeInt((digitsBefore << 16) | digitsAfter);
+ buffer.writeInt(flags);
+
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textId = buffer.readInt();
+ float value = buffer.readFloat();
+ int tmp = buffer.readInt();
+ short post = (short) (tmp & 0xFFFF);
+ short pre = (short) ((tmp >> 16) & 0xFFFF);
+
+ int flags = buffer.readInt();
+ operations.add(new TextFromFloat(textId, value, pre, post, flags));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ float v = mOutValue;
+ String s = StringUtils.floatToString(v, mDigitsBefore,
+ mDigitsAfter, mPre, mAfter);
+ context.loadText(mTextId, s);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
new file mode 100644
index 0000000..a0fc854
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TextMerge.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations;
+
+import com.android.internal.widget.remotecompose.core.CompanionOperation;
+import com.android.internal.widget.remotecompose.core.Operation;
+import com.android.internal.widget.remotecompose.core.Operations;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.WireBuffer;
+
+import java.util.List;
+
+/**
+ * Operation to deal with Text data
+ */
+public class TextMerge implements Operation {
+ public int mTextId;
+ public int mSrcId1;
+ public int mSrcId2;
+ public static final Companion COMPANION = new Companion();
+ public static final int MAX_STRING_SIZE = 4000;
+
+ public TextMerge(int textId, int srcId1, int srcId2) {
+ this.mTextId = textId;
+ this.mSrcId1 = srcId1;
+ this.mSrcId2 = srcId2;
+ }
+
+ @Override
+ public void write(WireBuffer buffer) {
+ COMPANION.apply(buffer, mTextId, mSrcId1, mSrcId2);
+ }
+
+ @Override
+ public String toString() {
+ return "TextMerge[" + mTextId + "] = [" + mSrcId1 + " ] + [ " + mSrcId2 + "]";
+ }
+
+ public static class Companion implements CompanionOperation {
+ private Companion() {
+ }
+
+ @Override
+ public String name() {
+ return "TextData";
+ }
+
+ @Override
+ public int id() {
+ return Operations.TEXT_MERGE;
+ }
+
+ /**
+ * Writes out the operation to the buffer
+ * @param buffer
+ * @param textId
+ * @param srcId1
+ * @param srcId2
+ */
+ public void apply(WireBuffer buffer, int textId, int srcId1, int srcId2) {
+ buffer.start(Operations.TEXT_MERGE);
+ buffer.writeInt(textId);
+ buffer.writeInt(srcId1);
+ buffer.writeInt(srcId2);
+ }
+
+ @Override
+ public void read(WireBuffer buffer, List<Operation> operations) {
+ int textId = buffer.readInt();
+ int srcId1 = buffer.readInt();
+ int srcId2 = buffer.readInt();
+
+ operations.add(new TextMerge(textId, srcId1, srcId2));
+ }
+ }
+
+ @Override
+ public void apply(RemoteContext context) {
+ String str1 = context.getText(mSrcId1);
+ String str2 = context.getText(mSrcId2);
+ context.loadText(mTextId, str1 + str2);
+ }
+
+ @Override
+ public String deepToString(String indent) {
+ return indent + toString();
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
index 00e2f20..fdc6860 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java
@@ -15,13 +15,16 @@
*/
package com.android.internal.widget.remotecompose.core.operations;
+/**
+ * Utilities to be used across all core operations
+ */
public class Utils {
public static float asNan(int v) {
return Float.intBitsToFloat(v | -0x800000);
}
public static int idFromNan(float value) {
- int b = Float.floatToRawIntBits(value);
+ int b = Float.floatToRawIntBits(value);
return b & 0xFFFFF;
}
@@ -29,13 +32,194 @@
return 0;
}
- String getFloatString(float value) {
- if (Float.isNaN(value)) {
- int id = idFromNan(value);
- if (id > 0) {
- return "NaN(" + id + ")";
- }
+ /**
+ * trim a string to n characters if needing to trim
+ * end in "..."
+ *
+ * @param str
+ * @param n
+ * @return
+ */
+ static String trimString(String str, int n) {
+ if (str.length() > n) {
+ str = str.substring(0, n - 3) + "...";
}
- return "" + value;
+ return str;
}
+
+ /**
+ * print the id and the value of a float
+ * @param idvalue
+ * @param value
+ * @return
+ */
+ public static String floatToString(float idvalue, float value) {
+ if (Float.isNaN(idvalue)) {
+ return "[" + idFromNan(idvalue) + "]" + floatToString(value);
+ }
+ return floatToString(value);
+ }
+
+ /**
+ * Convert float to string but render nan id in brackets [n]
+ * @param value
+ * @return
+ */
+ public static String floatToString(float value) {
+ if (Float.isNaN(value)) {
+ return "[" + idFromNan(value) + "]";
+ }
+ return Float.toString(value);
+ }
+
+ /**
+ * Debugging util to print a message and include the file/line it came from
+ * @param str
+ */
+ public static void log(String str) {
+ StackTraceElement s = new Throwable().getStackTrace()[1];
+ System.out.println("(" + s.getFileName() + ":" + s.getLineNumber() + ")." + str);
+ }
+
+ /**
+ * Debugging util to print the stack
+ * @param str
+ * @param n
+ */
+ public static void logStack(String str, int n) {
+ StackTraceElement[] st = new Throwable().getStackTrace();
+ for (int i = 1; i < n + 1; i++) {
+ StackTraceElement s = st[i];
+ String space = new String(new char[i]).replace('\0', ' ');
+ System.out.println(space + "(" + s.getFileName()
+ + ":" + s.getLineNumber() + ")." + str);
+ }
+ }
+
+ /**
+ * Is a variable Allowed int calculation and references.
+ *
+ * @param v
+ * @return
+ */
+ public static boolean isVariable(float v) {
+ if (Float.isNaN(v)) {
+ int id = idFromNan(v);
+ return id > 40 || id < 10;
+ }
+ return false;
+ }
+
+ /**
+ * print a color in the familiar 0xAARRGGBB pattern
+ *
+ * @param color
+ * @return
+ */
+ public static String colorInt(int color) {
+ String str = "000000000000" + Integer.toHexString(color);
+ return "0x" + str.substring(str.length() - 8);
+ }
+
+ /**
+ * Interpolate two colors.
+ * gamma corrected colors are interpolated in the form c1 * (1-t) + c2 * t
+ *
+ * @param c1
+ * @param c2
+ * @param t
+ * @return
+ */
+ public static int interpolateColor(int c1, int c2, float t) {
+ if (Float.isNaN(t) || t == 0.0f) {
+ return c1;
+ } else if (t == 1.0f) {
+ return c2;
+ }
+ int a = 0xFF & (c1 >> 24);
+ int r = 0xFF & (c1 >> 16);
+ int g = 0xFF & (c1 >> 8);
+ int b = 0xFF & c1;
+ float f_r = (float) Math.pow(r / 255.0f, 2.2);
+ float f_g = (float) Math.pow(g / 255.0f, 2.2);
+ float f_b = (float) Math.pow(b / 255.0f, 2.2);
+ float c1fr = f_r;
+ float c1fg = f_g;
+ float c1fb = f_b;
+ float c1fa = a / 255f;
+
+ a = 0xFF & (c2 >> 24);
+ r = 0xFF & (c2 >> 16);
+ g = 0xFF & (c2 >> 8);
+ b = 0xFF & c2;
+ f_r = (float) Math.pow(r / 255.0f, 2.2);
+ f_g = (float) Math.pow(g / 255.0f, 2.2);
+ f_b = (float) Math.pow(b / 255.0f, 2.2);
+ float c2fr = f_r;
+ float c2fg = f_g;
+ float c2fb = f_b;
+ float c2fa = a / 255f;
+ f_r = c1fr + t * (c2fr - c1fr);
+ f_g = c1fg + t * (c2fg - c1fg);
+ f_b = c1fb + t * (c2fb - c1fb);
+ float f_a = c1fa + t * (c2fa - c1fa);
+
+ int outr = clamp((int) ((float) Math.pow(f_r, 1.0 / 2.2) * 255.0f));
+ int outg = clamp((int) ((float) Math.pow(f_g, 1.0 / 2.2) * 255.0f));
+ int outb = clamp((int) ((float) Math.pow(f_b, 1.0 / 2.2) * 255.0f));
+ int outa = clamp((int) (f_a * 255.0f));
+
+
+ return (outa << 24 | outr << 16 | outg << 8 | outb);
+ }
+
+ /**
+ * Efficient clamping function
+ *
+ * @param c
+ * @return number between 0 and 255
+ */
+ public static int clamp(int c) {
+ int n = 255;
+ c &= ~(c >> 31);
+ c -= n;
+ c &= (c >> 31);
+ c += n;
+ return c;
+ }
+
+ /**
+ * convert hue saturation and value to RGB
+ *
+ * @param hue 0..1
+ * @param saturation 0..1 0=on the gray scale
+ * @param value 0..1 0=black
+ * @return
+ */
+ public static int hsvToRgb(float hue, float saturation, float value) {
+ int h = (int) (hue * 6);
+ float f = hue * 6 - h;
+ int p = (int) (0.5f + 255 * value * (1 - saturation));
+ int q = (int) (0.5f + 255 * value * (1 - f * saturation));
+ int t = (int) (0.5f + 255 * value * (1 - (1 - f) * saturation));
+ int v = (int) (0.5f + 255 * value);
+ switch (h) {
+ case 0:
+ return 0XFF000000 | (v << 16) + (t << 8) + p;
+ case 1:
+ return 0XFF000000 | (q << 16) + (v << 8) + p;
+ case 2:
+ return 0XFF000000 | (p << 16) + (v << 8) + t;
+ case 3:
+ return 0XFF000000 | (p << 16) + (q << 8) + v;
+ case 4:
+ return 0XFF000000 | (t << 16) + (p << 8) + v;
+ case 5:
+ return 0XFF000000 | (v << 16) + (p << 8) + q;
+
+ }
+ return 0;
+ }
+
+
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
index 8abb0bf..a7d0ac6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java
@@ -15,43 +15,60 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+import com.android.internal.widget.remotecompose.core.PaintContext;
+import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
import com.android.internal.widget.remotecompose.core.WireBuffer;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
import java.util.Arrays;
+/**
+ * Paint Bundle represents a delta of changes to a paint object
+ */
public class PaintBundle {
int[] mArray = new int[200];
+ int[] mOutArray = null;
int mPos = 0;
- public void applyPaintChange(PaintChanges p) {
+ /**
+ * Apply changes to a PaintChanges interface
+ * @param paintContext
+ * @param p
+ */
+ public void applyPaintChange(PaintContext paintContext, PaintChanges p) {
int i = 0;
int mask = 0;
+ if (mOutArray == null) {
+ mOutArray = mArray;
+ }
while (i < mPos) {
- int cmd = mArray[i++];
+ int cmd = mOutArray[i++];
mask = mask | (1 << (cmd - 1));
switch (cmd & 0xFFFF) {
case TEXT_SIZE: {
- p.setTextSize(Float.intBitsToFloat(mArray[i++]));
+ p.setTextSize(Float.intBitsToFloat(mOutArray[i++]));
break;
}
case TYPEFACE:
int style = (cmd >> 16);
int weight = style & 0x3ff;
boolean italic = (style >> 10) > 0;
- int font_type = mArray[i++];
+ int font_type = mOutArray[i++];
p.setTypeFace(font_type, weight, italic);
break;
+ case COLOR_ID: // mOutArray should have already decoded it
case COLOR: {
- p.setColor(mArray[i++]);
+ p.setColor(mOutArray[i++]);
break;
}
case STROKE_WIDTH: {
- p.setStrokeWidth(Float.intBitsToFloat(mArray[i++]));
+ p.setStrokeWidth(Float.intBitsToFloat(mOutArray[i++]));
break;
}
case STROKE_MITER: {
- p.setStrokeMiter(Float.intBitsToFloat(mArray[i++]));
+ p.setStrokeMiter(Float.intBitsToFloat(mOutArray[i++]));
break;
}
case STROKE_CAP: {
@@ -63,6 +80,7 @@
break;
}
case SHADER: {
+ p.setShader(mOutArray[i++]);
break;
}
case STROKE_JOIN: {
@@ -81,17 +99,16 @@
p.setFilterBitmap(!((cmd >> 16) == 0));
break;
}
-
case GRADIENT: {
- i = callSetGradient(cmd, mArray, i, p);
+ i = callSetGradient(cmd, mOutArray, i, p);
break;
}
case COLOR_FILTER: {
- p.setColorFilter(mArray[i++], cmd >> 16);
+ p.setColorFilter(mOutArray[i++], cmd >> 16);
break;
}
case ALPHA: {
- p.setAlpha(Float.intBitsToFloat(mArray[i++]));
+ p.setAlpha(Float.intBitsToFloat(mOutArray[i++]));
break;
}
}
@@ -106,7 +123,6 @@
switch (id) {
case TEXT_SIZE:
return "TEXT_SIZE";
-
case COLOR:
return "COLOR";
case STROKE_WIDTH:
@@ -133,7 +149,6 @@
return "ALPHA";
case COLOR_FILTER:
return "COLOR_FILTER";
-
}
return "????" + id + "????";
}
@@ -154,6 +169,14 @@
return str + "]";
}
+ private static String asFloatStr(int value) {
+ float fValue = Float.intBitsToFloat(value);
+ if (Float.isNaN(fValue)) {
+ return "[" + Utils.idFromNan(fValue) + "]";
+ }
+ return Float.toString(fValue);
+ }
+
@Override
public String toString() {
StringBuilder ret = new StringBuilder("\n");
@@ -164,7 +187,8 @@
switch (type) {
case TEXT_SIZE: {
- ret.append(" TextSize(" + Float.intBitsToFloat(mArray[i++]));
+ ret.append(" TextSize("
+ + asFloatStr(mArray[i++]));
}
break;
@@ -181,14 +205,18 @@
ret.append(" Color(" + colorInt(mArray[i++]));
}
break;
+ case COLOR_ID: {
+ ret.append(" ColorId([" + mArray[i++] + "]");
+ }
+ break;
case STROKE_WIDTH: {
ret.append(" StrokeWidth("
- + (Float.intBitsToFloat(mArray[i++])));
+ + (asFloatStr(mArray[i++])));
}
break;
case STROKE_MITER: {
ret.append(" StrokeMiter("
- + (Float.intBitsToFloat(mArray[i++])));
+ + (asFloatStr(mArray[i++])));
}
break;
case STROKE_CAP: {
@@ -207,11 +235,12 @@
}
break;
case SHADER: {
+ ret.append(" Shader(" + mArray[i++]);
}
break;
case ALPHA: {
ret.append(" Alpha("
- + (Float.intBitsToFloat(mArray[i++])));
+ + (asFloatStr(mArray[i++])));
}
break;
case IMAGE_FILTER_QUALITY: {
@@ -244,7 +273,6 @@
return ret.toString();
}
-
int callPrintGradient(int cmd, int[] array, int i, StringBuilder p) {
int ret = i;
int type = (cmd >> 16);
@@ -258,26 +286,25 @@
colors = new int[len];
for (int j = 0; j < colors.length; j++) {
colors[j] = array[ret++];
-
}
}
len = array[ret++];
- float[] stops = null;
+ String[] stops = null;
if (len > 0) {
- stops = new float[len];
+ stops = new String[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = Float.intBitsToFloat(array[ret++]);
+ stops[j] = asFloatStr(array[ret++]);
}
}
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" start = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", " + asFloatStr(array[ret++]) + "],\n");
p.append(" end = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", " + asFloatStr(array[ret++]) + "],\n");
int tileMode = array[ret++];
p.append(" tileMode = " + tileMode + "\n ");
}
@@ -295,21 +322,21 @@
}
}
len = array[ret++];
- float[] stops = null;
+ String[] stops = null;
if (len > 0) {
- stops = new float[len];
+ stops = new String[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = Float.intBitsToFloat(array[ret++]);
+ stops[j] = asFloatStr(array[ret++]);
}
}
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" center = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n");
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", " + asFloatStr(array[ret++]) + "],\n");
p.append(" radius =");
- p.append(" " + Float.intBitsToFloat(array[ret++]) + ",\n");
+ p.append(" " + asFloatStr(array[ret++]) + ",\n");
int tileMode = array[ret++];
p.append(" tileMode = " + tileMode + "\n ");
}
@@ -327,20 +354,19 @@
}
}
len = array[ret++];
- float[] stops = null;
+ String[] stops = null;
if (len > 0) {
- stops = new float[len];
+ stops = new String[len];
for (int j = 0; j < stops.length; j++) {
- stops[j] = Float.intBitsToFloat(array[ret++]);
+ stops[j] = asFloatStr(array[ret++]);
}
}
-
p.append(" colors = " + colorInt(colors) + ",\n");
p.append(" stops = " + Arrays.toString(stops) + ",\n");
p.append(" center = ");
- p.append("[" + Float.intBitsToFloat(array[ret++]));
- p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n ");
-
+ p.append("[" + asFloatStr(array[ret++]));
+ p.append(", "
+ + asFloatStr(array[ret++]) + "],\n ");
}
break;
default: {
@@ -376,7 +402,6 @@
return ret;
}
-
switch (gradientType) {
case LINEAR_GRADIENT: {
@@ -433,7 +458,7 @@
public static final int COLOR = 4; // int
public static final int STROKE_WIDTH = 5; // float
public static final int STROKE_MITER = 6;
- public static final int STROKE_CAP = 7; // int
+ public static final int STROKE_CAP = 7; // int
public static final int STYLE = 8; // int
public static final int SHADER = 9; // int
public static final int IMAGE_FILTER_QUALITY = 10; // int
@@ -445,7 +470,7 @@
public static final int TYPEFACE = 16;
public static final int FILTER_BITMAP = 17;
public static final int BLEND_MODE = 18;
-
+ public static final int COLOR_ID = 19; // int
public static final int BLEND_MODE_CLEAR = 0;
public static final int BLEND_MODE_SRC = 1;
@@ -634,8 +659,8 @@
/**
* @param fontType 0 = default 1 = sans serif 2 = serif 3 = monospace
- * @param weight 100-1000
- * @param italic tur
+ * @param weight 100-1000
+ * @param italic tur
*/
public void setTextStyle(int fontType, int weight, boolean italic) {
int style = (weight & 0x3FF) | (italic ? 2048 : 0); // pack the weight and italic
@@ -658,6 +683,10 @@
mPos++;
}
+ /**
+ * Set the Color based on Color
+ * @param color
+ */
public void setColor(int color) {
mArray[mPos] = COLOR;
mPos++;
@@ -666,6 +695,18 @@
}
/**
+ * Set the Color based on ID
+ * @param color
+ */
+ public void setColorId(int color) {
+ mArray[mPos] = COLOR_ID;
+ mPos++;
+ mArray[mPos] = color;
+ mPos++;
+ }
+
+
+ /**
* Set the paint's Cap.
*
* @param cap set the paint's line cap style, used whenever the paint's
@@ -676,16 +717,29 @@
mPos++;
}
+ /**
+ * Set the style STROKE and/or FILL
+ * @param style
+ */
public void setStyle(int style) {
mArray[mPos] = STYLE | (style << 16);
mPos++;
}
- public void setShader(int shader, String shaderString) {
- mArray[mPos] = SHADER | (shader << 16);
+ /**
+ * Set the shader id to use
+ * @param shaderId
+ */
+ public void setShader(int shaderId) {
+ mArray[mPos] = SHADER;
+ mPos++;
+ mArray[mPos] = shaderId;
mPos++;
}
+ /**
+ * Set the Alpha value
+ */
public void setAlpha(float alpha) {
mArray[mPos] = ALPHA;
mPos++;
@@ -729,7 +783,6 @@
* destination pixels
* (content of the render target).
*
- *
* @param blendmode The blend mode to be installed in the paint
*/
public void setBlendMode(int blendmode) {
@@ -825,5 +878,216 @@
return "null";
}
-}
+ /**
+ * Check all the floats for Nan(id) floats and call listenTo
+ * @param context
+ * @param support
+ */
+ public void registerVars(RemoteContext context, VariableSupport support) {
+ int i = 0;
+ while (i < mPos) {
+ int cmd = mArray[i++];
+ int type = cmd & 0xFFFF;
+ switch (type) {
+ case STROKE_MITER:
+ case STROKE_WIDTH:
+ case ALPHA:
+ case TEXT_SIZE:
+ float v = Float.intBitsToFloat(mArray[i++]);
+ if (Float.isNaN(v)) {
+ context.listensTo(Utils.idFromNan(v), support);
+ }
+ break;
+ case COLOR_ID:
+ context.listensTo(mArray[i++], support);
+ break;
+ case COLOR:
+ case TYPEFACE:
+ case SHADER:
+ case COLOR_FILTER:
+ i++;
+ break;
+ case STROKE_JOIN:
+ case FILTER_BITMAP:
+ case STROKE_CAP:
+ case STYLE:
+ case IMAGE_FILTER_QUALITY:
+ case BLEND_MODE:
+ case ANTI_ALIAS:
+ break;
+
+ case GRADIENT: {
+ // TODO gradients should be handled correctly
+ i = callPrintGradient(cmd, mArray, i, new StringBuilder());
+ }
+ }
+ }
+ }
+
+ /**
+ * Update variables if any are float ids
+ * @param context
+ */
+ public void updateVariables(RemoteContext context) {
+ if (mOutArray == null) {
+ mOutArray = Arrays.copyOf(mArray, mArray.length);
+ } else {
+ System.arraycopy(mArray, 0, mOutArray, 0, mArray.length);
+ }
+ int i = 0;
+ while (i < mPos) {
+ int cmd = mArray[i++];
+ int type = cmd & 0xFFFF;
+ switch (type) {
+ case STROKE_MITER:
+ case STROKE_WIDTH:
+ case ALPHA:
+ case TEXT_SIZE:
+ mOutArray[i] = fixFloatVar(mArray[i], context);
+ i++;
+ break;
+ case COLOR_ID:
+ mOutArray[i] = fixColor(mArray[i], context);
+ i++;
+ break;
+ case COLOR:
+ case TYPEFACE:
+ case SHADER:
+ case COLOR_FILTER:
+ i++;
+ break;
+ case STROKE_JOIN:
+ case FILTER_BITMAP:
+ case STROKE_CAP:
+ case STYLE:
+ case IMAGE_FILTER_QUALITY:
+ case BLEND_MODE:
+ case ANTI_ALIAS:
+ break;
+
+ case GRADIENT: {
+ // TODO gradients should be handled correctly
+ i = updateFloatsInGradient(cmd, mOutArray, mArray, i, context);
+ }
+ }
+ }
+ }
+
+ private int fixFloatVar(int val, RemoteContext context) {
+ float v = Float.intBitsToFloat(val);
+ if (Float.isNaN(v)) {
+ int id = Utils.idFromNan(v);
+ return Float.floatToRawIntBits(context.getFloat(id));
+ }
+ return val;
+ }
+
+ private int fixColor(int colorId, RemoteContext context) {
+ int n = context.getColor(colorId);
+ return n;
+ }
+
+ int updateFloatsInGradient(int cmd, int[] out, int[] array,
+ int i,
+ RemoteContext context) {
+ int ret = i;
+ int type = (cmd >> 16);
+ switch (type) {
+ case 0: {
+ int len = array[ret++];
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ ret++;
+ }
+ }
+ len = array[ret++];
+
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ }
+
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+
+ // end
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ ret++; // tileMode
+ }
+
+ break;
+ case 1: {
+ // RadialGradient
+ int len = array[ret++];
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ ret++;
+ }
+ }
+ len = array[ret++];
+ if (len > 0) {
+ for (int j = 0; j < len; j++) {
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ }
+
+
+ // center
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ // radius
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ ret++; // tileMode
+
+ }
+
+ break;
+ case 2: {
+ // SweepGradient
+ int len = array[ret++];
+ int[] colors = null;
+ if (len > 0) {
+ colors = new int[len];
+ for (int j = 0; j < colors.length; j++) {
+ colors[j] = array[ret++];
+
+ }
+ }
+ len = array[ret++];
+ float[] stops = null;
+ if (len > 0) {
+ stops = new float[len];
+ for (int j = 0; j < stops.length; j++) {
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ }
+
+ // center
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ out[ret] = fixFloatVar(array[ret], context);
+ ret++;
+ }
+ break;
+ default: {
+ System.err.println("gradient type unknown");
+ }
+ }
+
+ return ret;
+ }
+
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
index 994bf6d..28fe63a 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java
@@ -27,7 +27,6 @@
}
-
@Override
public void setStrokeWidth(float width) {
@@ -49,7 +48,7 @@
}
@Override
- public void setShader(int shader, String shaderString) {
+ public void setShader(int shader) {
}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
index 87e58ac..d5dc388 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java
@@ -15,9 +15,14 @@
*/
package com.android.internal.widget.remotecompose.core.operations.paint;
+/**
+ * Interface to a paint object
+ * For more details see Android Paint
+ */
public interface PaintChanges {
-
+ // MASK to be set/cleared
+ int CLEAR_TEXT_SIZE = 1 << (PaintBundle.TEXT_SIZE - 1);
int CLEAR_TEXT_STYLE = 1 << (PaintBundle.TYPEFACE - 1);
int CLEAR_COLOR = 1 << (PaintBundle.COLOR - 1);
int CLEAR_STROKE_WIDTH = 1 << (PaintBundle.STROKE_WIDTH - 1);
@@ -32,21 +37,101 @@
int CLEAR_COLOR_FILTER = 1 << (PaintBundle.COLOR_FILTER - 1);
int VALID_BITS = 0x1FFF; // only the first 13 bit are valid now
-
+ /**
+ * Set the size of text
+ * @param size
+ */
void setTextSize(float size);
+
+ /**
+ * Set the width of lines
+ * @param width
+ */
void setStrokeWidth(float width);
+
+ /**
+ * Set the color to use
+ * @param color
+ */
void setColor(int color);
+
+ /**
+ * Set the Stroke Cap
+ * @param cap
+ */
void setStrokeCap(int cap);
+
+ /**
+ * Set the Stroke style FILL and/or STROKE
+ * @param style
+ */
void setStyle(int style);
- void setShader(int shader, String shaderString);
+
+ /**
+ * Set the id of the shader to use
+ * @param shader
+ */
+ void setShader(int shader);
+
+ /**
+ * Set the way image is interpolated
+ * @param quality
+ */
void setImageFilterQuality(int quality);
+
+ /**
+ * Set the alpha to draw under
+ * @param a
+ */
void setAlpha(float a);
+
+ /**
+ * Set the Stroke Miter
+ * @param miter
+ */
void setStrokeMiter(float miter);
+
+ /**
+ * Set the Stroke Join
+ * @param join
+ */
void setStrokeJoin(int join);
+
+ /**
+ * Should bitmaps be interpolated
+ * @param filter
+ */
void setFilterBitmap(boolean filter);
+
+ /**
+ * Set the blend mode can be porterduff + others
+ * @param mode
+ */
void setBlendMode(int mode);
+
+ /**
+ * Set the AntiAlias. Typically true
+ * Set to off when you need pixilated look (e.g. QR codes)
+ * @param aa
+ */
void setAntiAlias(boolean aa);
+
+ /**
+ * Clear some sub set of the settings
+ * @param mask
+ */
void clear(long mask);
+
+ /**
+ * Set a linear gradient fill
+ * @param colorsArray
+ * @param stopsArray
+ * @param startX
+ * @param startY
+ * @param endX
+ * @param endY
+ * @param tileMode
+ */
void setLinearGradient(
int[] colorsArray,
float[] stopsArray,
@@ -57,6 +142,15 @@
int tileMode
);
+ /**
+ * Set a radial gradient fill
+ * @param colorsArray
+ * @param stopsArray
+ * @param centerX
+ * @param centerY
+ * @param radius
+ * @param tileMode
+ */
void setRadialGradient(
int[] colorsArray,
float[] stopsArray,
@@ -66,6 +160,13 @@
int tileMode
);
+ /**
+ * Set a sweep gradient fill
+ * @param colorsArray
+ * @param stopsArray
+ * @param centerX
+ * @param centerY
+ */
void setSweepGradient(
int[] colorsArray,
float[] stopsArray,
@@ -73,9 +174,19 @@
float centerY
);
-
+ /**
+ * Set Color filter mod
+ * @param color
+ * @param mode
+ */
void setColorFilter(int color, int mode);
+ /**
+ * Set TypeFace 0,1,2
+ * TODO above should point to a string to be decoded
+ * @param fontType
+ * @param weight
+ * @param italic
+ */
void setTypeFace(int fontType, int weight, boolean italic);
-}
-
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
new file mode 100644
index 0000000..616048d
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/AnimatedFloatExpression.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+/**
+ * high performance floating point expression evaluator used in animation
+ */
+public class AnimatedFloatExpression {
+ static IntMap<String> sNames = new IntMap<>();
+ public static final int OFFSET = 0x100;
+ public static final float ADD = asNan(OFFSET + 1);
+ public static final float SUB = asNan(OFFSET + 2);
+ public static final float MUL = asNan(OFFSET + 3);
+ public static final float DIV = asNan(OFFSET + 4);
+ public static final float MOD = asNan(OFFSET + 5);
+ public static final float MIN = asNan(OFFSET + 6);
+ public static final float MAX = asNan(OFFSET + 7);
+ public static final float POW = asNan(OFFSET + 8);
+ public static final float SQRT = asNan(OFFSET + 9);
+ public static final float ABS = asNan(OFFSET + 10);
+ public static final float SIGN = asNan(OFFSET + 11);
+ public static final float COPY_SIGN = asNan(OFFSET + 12);
+ public static final float EXP = asNan(OFFSET + 13);
+ public static final float FLOOR = asNan(OFFSET + 14);
+ public static final float LOG = asNan(OFFSET + 15);
+ public static final float LN = asNan(OFFSET + 16);
+ public static final float ROUND = asNan(OFFSET + 17);
+ public static final float SIN = asNan(OFFSET + 18);
+ public static final float COS = asNan(OFFSET + 19);
+ public static final float TAN = asNan(OFFSET + 20);
+ public static final float ASIN = asNan(OFFSET + 21);
+ public static final float ACOS = asNan(OFFSET + 22);
+
+ public static final float ATAN = asNan(OFFSET + 23);
+
+ public static final float ATAN2 = asNan(OFFSET + 24);
+ public static final float MAD = asNan(OFFSET + 25);
+ public static final float IFELSE = asNan(OFFSET + 26);
+
+ public static final float CLAMP = asNan(OFFSET + 27);
+ public static final float CBRT = asNan(OFFSET + 28);
+ public static final float DEG = asNan(OFFSET + 29);
+ public static final float RAD = asNan(OFFSET + 30);
+ public static final float CEIL = asNan(OFFSET + 31);
+
+
+ public static final float LAST_OP = 31;
+
+
+ public static final float VAR1 = asNan(OFFSET + 27);
+ public static final float VAR2 = asNan(OFFSET + 28);
+
+ // TODO CLAMP, CBRT, DEG, RAD, EXPM1, CEIL, FLOOR
+ private static final float FP_PI = (float) Math.PI;
+ private static final float FP_TO_RAD = 57.29577951f; // 180/PI
+ private static final float FP_TO_DEG = 0.01745329252f; // 180/PI
+
+ float[] mStack;
+ float[] mLocalStack = new float[128];
+ float[] mVar;
+
+ /**
+ * is float a math operator
+ * @param v
+ * @return
+ */
+ public static boolean isMathOperator(float v) {
+ if (Float.isNaN(v)) {
+ int pos = fromNaN(v);
+ return pos > OFFSET && pos <= OFFSET + LAST_OP;
+ }
+ return false;
+ }
+
+ interface Op {
+ int eval(int sp);
+ }
+
+ /**
+ * Evaluate a float expression
+ * @param exp
+ * @param var
+ * @return
+ */
+ public float eval(float[] exp, float... var) {
+ mStack = exp;
+ mVar = var;
+ int sp = -1;
+ for (int i = 0; i < mStack.length; i++) {
+ float v = mStack[i];
+ if (Float.isNaN(v)) {
+ sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+ } else {
+ mStack[++sp] = v;
+ }
+ }
+ return mStack[sp];
+ }
+
+ /**
+ * Evaluate a float expression
+ * @param exp
+ * @param len
+ * @param var
+ * @return
+ */
+ public float eval(float[] exp, int len, float... var) {
+ System.arraycopy(exp, 0, mLocalStack, 0, len);
+ mStack = mLocalStack;
+ mVar = var;
+ int sp = -1;
+ for (int i = 0; i < len; i++) {
+ float v = mStack[i];
+ if (Float.isNaN(v)) {
+ sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+ } else {
+ mStack[++sp] = v;
+ }
+ }
+ return mStack[sp];
+ }
+
+ /**
+ * Evaluate a float expression
+ * @param exp
+ * @param var
+ * @return
+ */
+ public float evalDB(float[] exp, float... var) {
+ mStack = exp;
+ mVar = var;
+ int sp = -1;
+ for (float v : exp) {
+ if (Float.isNaN(v)) {
+ System.out.print(" " + sNames.get((fromNaN(v) - OFFSET)));
+ sp = mOps[fromNaN(v) - OFFSET].eval(sp);
+ } else {
+ System.out.print(" " + v);
+ mStack[++sp] = v;
+ }
+ }
+ return mStack[sp];
+ }
+
+ Op[] mOps = {
+ null,
+ (sp) -> { // ADD
+ mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // SUB
+ mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // MUL
+ mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // DIV
+ mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // MOD
+ mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
+ return sp - 1;
+ },
+ (sp) -> { // MIN
+ mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // MAX
+ mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // POW
+ mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // SQRT
+ mStack[sp] = (float) Math.sqrt(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ABS
+ mStack[sp] = (float) Math.abs(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // SIGN
+ mStack[sp] = (float) Math.signum(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // copySign
+ mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // EXP
+ mStack[sp] = (float) Math.exp(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // FLOOR
+ mStack[sp] = (float) Math.floor(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // LOG
+ mStack[sp] = (float) Math.log10(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // LN
+ mStack[sp] = (float) Math.log(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ROUND
+ mStack[sp] = (float) Math.round(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // SIN
+ mStack[sp] = (float) Math.sin(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // COS
+ mStack[sp] = (float) Math.cos(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // TAN
+ mStack[sp] = (float) Math.tan(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ASIN
+ mStack[sp] = (float) Math.asin(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ACOS
+ mStack[sp] = (float) Math.acos(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ATAN
+ mStack[sp] = (float) Math.atan(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // ATAN2
+ mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]);
+ return sp - 1;
+ },
+ (sp) -> { // MAD
+ mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
+ return sp - 2;
+ },
+ (sp) -> { // Ternary conditional
+ mStack[sp - 2] = (mStack[sp] > 0)
+ ? mStack[sp - 1] : mStack[sp - 2];
+ return sp - 2;
+ },
+ (sp) -> { // CLAMP(min,max, val)
+ mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]),
+ mStack[sp - 1]);
+ return sp - 2;
+ },
+ (sp) -> { // CBRT cuberoot
+ mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.);
+ return sp;
+ },
+ (sp) -> { // DEG
+ mStack[sp] = mStack[sp] * FP_TO_RAD;
+ return sp;
+ },
+ (sp) -> { // RAD
+ mStack[sp] = mStack[sp] * FP_TO_DEG;
+ return sp;
+ },
+ (sp) -> { // CEIL
+ mStack[sp] = (float) Math.ceil(mStack[sp]);
+ return sp;
+ },
+ (sp) -> { // first var =
+ mStack[sp] = mVar[0];
+ return sp;
+ },
+ (sp) -> { // second var y?
+ mStack[sp] = mVar[1];
+ return sp;
+ },
+ (sp) -> { // 3rd var z?
+ mStack[sp] = mVar[2];
+ return sp;
+ },
+ };
+
+ static {
+ int k = 0;
+ sNames.put(k++, "NOP");
+ sNames.put(k++, "+");
+ sNames.put(k++, "-");
+ sNames.put(k++, "*");
+ sNames.put(k++, "/");
+ sNames.put(k++, "%");
+ sNames.put(k++, "min");
+ sNames.put(k++, "max");
+ sNames.put(k++, "pow");
+ sNames.put(k++, "sqrt");
+ sNames.put(k++, "abs");
+ sNames.put(k++, "sign");
+ sNames.put(k++, "copySign");
+ sNames.put(k++, "exp");
+ sNames.put(k++, "floor");
+ sNames.put(k++, "log");
+ sNames.put(k++, "ln");
+ sNames.put(k++, "round");
+ sNames.put(k++, "sin");
+ sNames.put(k++, "cos");
+ sNames.put(k++, "tan");
+ sNames.put(k++, "asin");
+ sNames.put(k++, "acos");
+ sNames.put(k++, "atan");
+ sNames.put(k++, "atan2");
+ sNames.put(k++, "mad");
+ sNames.put(k++, "ifElse");
+ sNames.put(k++, "clamp");
+ sNames.put(k++, "cbrt");
+ sNames.put(k++, "deg");
+ sNames.put(k++, "rad");
+ sNames.put(k++, "ceil");
+ sNames.put(k++, "a[0]");
+ sNames.put(k++, "a[1]");
+ sNames.put(k++, "a[2]");
+ }
+
+ /**
+ * given a float command return its math name (e.g sin, cos etc.)
+ * @param f
+ * @return
+ */
+ public static String toMathName(float f) {
+ int id = fromNaN(f) - OFFSET;
+ return sNames.get(id);
+ }
+
+ /**
+ * Convert an expression encoded as an array of floats int ot a string
+ * @param exp
+ * @param labels
+ * @return
+ */
+ public static String toString(float[] exp, String[] labels) {
+ StringBuilder s = new StringBuilder();
+ for (int i = 0; i < exp.length; i++) {
+ float v = exp[i];
+ if (Float.isNaN(v)) {
+ if (isMathOperator(v)) {
+ s.append(toMathName(v));
+ } else {
+ s.append("[");
+ s.append(fromNaN(v));
+ s.append("]");
+ }
+ } else {
+ if (labels[i] != null) {
+ s.append(labels[i]);
+ }
+ s.append(v);
+ }
+ s.append(" ");
+ }
+ return s.toString();
+ }
+
+ static String toString(float[] exp, int sp) {
+ String[] str = new String[exp.length];
+ if (Float.isNaN(exp[sp])) {
+ int id = fromNaN(exp[sp]) - OFFSET;
+ switch (NO_OF_OPS[id]) {
+ case -1:
+ return "nop";
+ case 1:
+ return sNames.get(id) + "(" + toString(exp, sp + 1) + ") ";
+ case 2:
+ if (infix(id)) {
+ return "(" + toString(exp, sp + 1)
+ + sNames.get(id) + " "
+ + toString(exp, sp + 2) + ") ";
+ } else {
+ return sNames.get(id) + "("
+ + toString(exp, sp + 1) + ", "
+ + toString(exp, sp + 2) + ")";
+ }
+ case 3:
+ if (infix(id)) {
+ return "((" + toString(exp, sp + 1) + ") ? "
+ + toString(exp, sp + 2) + ":"
+ + toString(exp, sp + 3) + ")";
+ } else {
+ return sNames.get(id)
+ + "(" + toString(exp, sp + 1)
+ + ", " + toString(exp, sp + 2)
+ + ", " + toString(exp, sp + 3) + ")";
+ }
+ }
+ }
+ return Float.toString(exp[sp]);
+ }
+
+ static final int[] NO_OF_OPS = {
+ -1, // no op
+ 2, 2, 2, 2, 2, // + - * / %
+ 2, 2, 2, // min max, power
+ 1, 1, 1, 1, 1, 1, 1, 1, //sqrt,abs,CopySign,exp,floor,log,ln
+ 1, 1, 1, 1, 1, 1, 1, 2, // round,sin,cos,tan,asin,acos,atan,atan2
+ 3, 3, 3, 1, 1, 1, 1,
+ 0, 0, 0 // mad, ?:,
+ // a[0],a[1],a[2]
+ };
+
+ /**
+ * to be used by parser to determine if command is infix
+ * @param n
+ * @return
+ */
+ static boolean infix(int n) {
+ return ((n < 6) || (n == 25) || (n == 26));
+ }
+
+ /**
+ * Convert an id into a NaN object
+ * @param v
+ * @return
+ */
+ public static float asNan(int v) {
+ return Float.intBitsToFloat(v | -0x800000);
+ }
+
+ /**
+ * Get ID from a NaN float
+ * @param v
+ * @return
+ */
+ public static int fromNaN(float v) {
+ int b = Float.floatToRawIntBits(v);
+ return b & 0xFFFFF;
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java
new file mode 100644
index 0000000..0ea28a8
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/ColorUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+/**
+ * These are tools to use long Color as variables
+ * long colors are stored a 0xXXXXXXXX XXXXXX??
+ * in SRGB the colors are stored 0xAARRGGBB,00000000
+ * SRGB color sapce is color space 0
+ * Our Color will use color float with a
+ * Current android supports
+ * SRGB, LINEAR_SRGB, EXTENDED_SRGB, LINEAR_EXTENDED_SRGB, BT709, BT2020,
+ * DCI_P3, DISPLAY_P3, NTSC_1953, SMPTE_C, ADOBE_RGB, PRO_PHOTO_RGB, ACES,
+ * ACESCG, CIE_XYZ, CIE_LAB, BT2020_HLG, BT2020_PQ 0..17 respectively
+ *
+ * Our color space will be 62 (MAX_ID-1). (0x3E)
+ * Storing the default value in SRGB format and having the
+ * id of the color between the ARGB values and the 62 i.e.
+ * 0xAARRGGBB 00 00 00 3E
+ *
+ */
+public class ColorUtils {
+ public static int RC_COLOR = 62;
+
+ long packRCColor(int defaultARGB, int id) {
+ long l = defaultARGB;
+ return (l << 32) | id << 8 | RC_COLOR;
+ }
+
+ boolean isRCColor(long color) {
+ return ((color & 0x3F) == 62);
+ }
+
+ int getID(long color) {
+ if (isRCColor(color)) {
+ return (int) ((color & 0xFFFFFF00) >> 8);
+ }
+ return -1;
+ }
+
+ /**
+ * get default color from long color
+ * @param color
+ * @return
+ */
+ public int getDefaultColor(long color) {
+ if (isRCColor(color)) {
+ return (int) (color >> 32);
+ }
+ if (((color & 0xFF) == 0)) {
+ return (int) (color >> 32);
+ }
+ return 0;
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
index 8051ef1..0512fa6 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/IntMap.java
@@ -50,7 +50,6 @@
return insert(key, value);
}
-
public T get(int key) {
int index = findKey(key);
if (index == -1) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java
new file mode 100644
index 0000000..f4cd504
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/NanMap.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+import com.android.internal.widget.remotecompose.core.operations.Utils;
+
+/**
+ * This defines the major id maps and ranges used by remote compose
+ * Generally ids ranging from 0 ... FFF (4095) are for ids
+ * 0x1000-0x1100 are used for path operations in PathData
+ * 0x1100-0x1200 are used for math operations in Animated float
+ * 0x
+ */
+public class NanMap {
+
+ public static final int MOVE = 0x1000;
+ public static final int LINE = 0x1001;
+ public static final int QUADRATIC = 0x1002;
+ public static final int CONIC = 0x1003;
+ public static final int CUBIC = 0x1004;
+ public static final int CLOSE = 0x1005;
+ public static final int DONE = 0x1006;
+ public static final float MOVE_NAN = Utils.asNan(MOVE);
+ public static final float LINE_NAN = Utils.asNan(LINE);
+ public static final float QUADRATIC_NAN = Utils.asNan(QUADRATIC);
+ public static final float CONIC_NAN = Utils.asNan(CONIC);
+ public static final float CUBIC_NAN = Utils.asNan(CUBIC);
+ public static final float CLOSE_NAN = Utils.asNan(CLOSE);
+ public static final float DONE_NAN = Utils.asNan(DONE);
+
+ /**
+ *
+ */
+ public static final float ADD = asNan(0x1100);
+ public static final float SUB = asNan(0x1101);
+ public static final float MUL = asNan(0x1102);
+ public static final float DIV = asNan(0x1103);
+ public static final float MOD = asNan(0x1104);
+ public static final float MIN = asNan(0x1105);
+ public static final float MAX = asNan(0x1106);
+ public static final float POW = asNan(0x1107);
+
+
+ /**
+ * Get ID from Nan float
+ * @param v
+ * @return
+ */
+ public static int fromNaN(float v) {
+ int b = Float.floatToRawIntBits(v);
+ return b & 0xFFFFF;
+ }
+
+ /**
+ * Given id return as a Nan float
+ * @param v
+ * @return
+ */
+ public static float asNan(int v) {
+ return Float.intBitsToFloat(v | 0xFF800000);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java
new file mode 100644
index 0000000..8dd5405
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/StringUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities;
+
+import java.util.Arrays;
+
+/**
+ * Utilities for string manipulation
+ */
+public class StringUtils {
+ /**
+ * Converts a float into a string.
+ * Providing a defined number of characters before and after the
+ * decimal point.
+ *
+ * @param value The value to convert to string
+ * @param beforeDecimalPoint digits before the decimal point
+ * @param afterDecimalPoint digits after the decimal point
+ * @param pre character to pad width 0 = no pad typically ' ' or '0'
+ * @param post character to pad width 0 = no pad typically ' ' or '0'
+ * @return
+ */
+ public static String floatToString(float value,
+ int beforeDecimalPoint,
+ int afterDecimalPoint,
+ char pre, char post) {
+
+ int integerPart = (int) value;
+ float fractionalPart = value % 1;
+
+ // Convert integer part to string and pad with spaces
+ String integerPartString = String.valueOf(integerPart);
+ int iLen = integerPartString.length();
+ if (iLen < beforeDecimalPoint) {
+ int spacesToPad = beforeDecimalPoint - iLen;
+ if (pre != 0) {
+ char[] pad = new char[spacesToPad];
+ Arrays.fill(pad, pre);
+ integerPartString = new String(pad) + integerPartString;
+ }
+
+
+ } else if (iLen > beforeDecimalPoint) {
+ integerPartString = integerPartString.substring(iLen - beforeDecimalPoint);
+ }
+ if (afterDecimalPoint == 0) {
+ return integerPartString;
+ }
+ // Convert fractional part to string and pad with zeros
+
+ for (int i = 0; i < afterDecimalPoint; i++) {
+ fractionalPart *= 10;
+ }
+
+ fractionalPart = Math.round(fractionalPart);
+
+ for (int i = 0; i < afterDecimalPoint; i++) {
+ fractionalPart *= .1;
+ }
+
+ String fact = Float.toString(fractionalPart);
+ fact = fact.substring(2, Math.min(fact.length(), afterDecimalPoint + 2));
+ int trim = fact.length();
+ for (int i = fact.length() - 1; i >= 0; i--) {
+ if (fact.charAt(i) != '0') {
+ break;
+ }
+ trim--;
+ }
+ if (trim != fact.length()) {
+ fact = fact.substring(0, trim);
+ }
+ int len = fact.length();
+ if (post != 0 && len < afterDecimalPoint) {
+ char[] c = new char[afterDecimalPoint - len];
+ Arrays.fill(c, post);
+ fact = fact + new String(c);
+ }
+
+ return integerPartString + "." + fact;
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java
new file mode 100644
index 0000000..c3cd5ae9
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/BounceCurve.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Provide a specific bouncing easing function
+ */
+public class BounceCurve extends Easing {
+ private static final float N1 = 7.5625f;
+ private static final float D1 = 2.75f;
+
+ BounceCurve(int type) {
+ mType = type;
+ }
+
+ @Override
+ public float get(float x) {
+ float t = x;
+ if (t < 0) {
+ return 0f;
+ }
+ if (t < 1 / D1) {
+ return 1 / (1 + 1 / D1) * (N1 * t * t + t);
+ } else if (t < 2 / D1) {
+ t -= 1.5f / D1;
+ return N1 * t * t + 0.75f;
+ } else if (t < 2.5 / D1) {
+ t -= 2.25f / D1;
+ return N1 * t * t + 0.9375f;
+ } else if (t <= 1) {
+ t -= 2.625f / D1;
+ return N1 * t * t + 0.984375f;
+ }
+ return 1f;
+ }
+
+ @Override
+ public float getDiff(float x) {
+ if (x < 0) {
+ return 0f;
+ }
+ if (x < 1 / D1) {
+ return 2 * N1 * x / (1 + 1 / D1) + 1 / (1 + 1 / D1);
+ } else if (x < 2 / D1) {
+ return 2 * N1 * (x - 1.5f / D1);
+ } else if (x < 2.5 / D1) {
+ return 2 * N1 * (x - 2.25f / D1);
+ } else if (x <= 1) {
+ return 2 * N1 * (x - 2.625f / D1);
+ }
+ return 0f;
+ }
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java
new file mode 100644
index 0000000..fd1ee03
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/CubicEasing.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+class CubicEasing extends Easing {
+ float mType = 0;
+ float mX1 = 0f;
+ float mY1 = 0f;
+ float mX2 = 0f;
+ float mY2 = 0f;
+
+ private static final float[] STANDARD = {0.4f, 0.0f, 0.2f, 1f};
+ private static final float[] ACCELERATE = {0.4f, 0.05f, 0.8f, 0.7f};
+ private static final float[] DECELERATE = {0.0f, 0.0f, 0.2f, 0.95f};
+ private static final float[] LINEAR = {1f, 1f, 0f, 0f};
+ private static final float[] ANTICIPATE = {0.36f, 0f, 0.66f, -0.56f};
+ private static final float[] OVERSHOOT = {0.34f, 1.56f, 0.64f, 1f};
+
+ CubicEasing(int type) {
+ mType = type;
+ config(type);
+ }
+
+ CubicEasing(float x1, float y1, float x2, float y2) {
+ setup(x1, y1, x2, y2);
+ }
+
+ public void config(int type) {
+
+ switch (type) {
+ case CUBIC_STANDARD:
+ setup(STANDARD);
+ break;
+ case CUBIC_ACCELERATE:
+ setup(ACCELERATE);
+ break;
+ case CUBIC_DECELERATE:
+ setup(DECELERATE);
+ break;
+ case CUBIC_LINEAR:
+ setup(LINEAR);
+ break;
+ case CUBIC_ANTICIPATE:
+ setup(ANTICIPATE);
+ break;
+ case CUBIC_OVERSHOOT:
+ setup(OVERSHOOT);
+ break;
+ }
+ mType = type;
+ }
+
+ void setup(float[] values) {
+ setup(values[0], values[1], values[2], values[3]);
+ }
+
+ void setup(float x1, float y1, float x2, float y2) {
+ mX1 = x1;
+ mY1 = y1;
+ mX2 = x2;
+ mY2 = y2;
+ }
+
+ private float getX(float t) {
+ float t1 = 1 - t;
+ // no need for because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
+ float f1 = 3 * t1 * t1 * t;
+ float f2 = 3 * t1 * t * t;
+ float f3 = t * t * t;
+ return mX1 * f1 + mX2 * f2 + f3;
+ }
+
+ private float getY(float t) {
+ float t1 = 1 - t;
+ // no need for testing because start at 0,0 float f0 = (1 - t) * (1 - t) * (1 - t)
+ float f1 = 3 * t1 * t1 * t;
+ float f2 = 3 * t1 * t * t;
+ float f3 = t * t * t;
+ return mY1 * f1 + mY2 * f2 + f3;
+ }
+
+ private float getDiffX(float t) {
+ float t1 = 1 - t;
+ return 3 * t1 * t1 * mX1 + 6 * t1 * t * (mX2 - mX1) + 3 * t * t * (1 - mX2);
+ }
+
+ private float getDiffY(float t) {
+ float t1 = 1 - t;
+ return 3 * t1 * t1 * mY1 + 6 * t1 * t * (mY2 - mY1) + 3 * t * t * (1 - mY2);
+ }
+
+ /**
+ * binary search for the region and linear interpolate the answer
+ */
+ public float getDiff(float x) {
+ float t = 0.5f;
+ float range = 0.5f;
+ while (range > D_ERROR) {
+ float tx = getX(t);
+ range *= 0.5;
+ if (tx < x) {
+ t += range;
+ } else {
+ t -= range;
+ }
+ }
+ float x1 = getX(t - range);
+ float x2 = getX(t + range);
+ float y1 = getY(t - range);
+ float y2 = getY(t + range);
+ return (y2 - y1) / (x2 - x1);
+ }
+
+ /**
+ * binary search for the region and linear interpolate the answer
+ */
+ public float get(float x) {
+ if (x <= 0.0f) {
+ return 0f;
+ }
+ if (x >= 1.0f) {
+ return 1.0f;
+ }
+ float t = 0.5f;
+ float range = 0.5f;
+ while (range > ERROR) {
+ float tx = getX(t);
+ range *= 0.5f;
+ if (tx < x) {
+ t += range;
+ } else {
+ t -= range;
+ }
+ }
+ float x1 = getX(t - range);
+ float x2 = getX(t + range);
+ float y1 = getY(t - range);
+ float y2 = getY(t + range);
+ return (y2 - y1) * (x - x1) / (x2 - x1) + y1;
+ }
+
+ private static final float ERROR = 0.01f;
+ private static final float D_ERROR = 0.0001f;
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java
new file mode 100644
index 0000000..4ed9550
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/Easing.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * The standard interface to Easing functions
+ */
+public abstract class Easing {
+ int mType;
+ /**
+ * get the value at point x
+ */
+ public abstract float get(float x);
+
+ /**
+ * get the slope of the easing function at at x
+ */
+ public abstract float getDiff(float x);
+
+ public int getType() {
+ return mType;
+ }
+
+ public static final int CUBIC_STANDARD = 1;
+ public static final int CUBIC_ACCELERATE = 2;
+ public static final int CUBIC_DECELERATE = 3;
+ public static final int CUBIC_LINEAR = 4;
+ public static final int CUBIC_ANTICIPATE = 5;
+ public static final int CUBIC_OVERSHOOT = 6;
+ public static final int CUBIC_CUSTOM = 11;
+ public static final int SPLINE_CUSTOM = 12;
+ public static final int EASE_OUT_BOUNCE = 13;
+ public static final int EASE_OUT_ELASTIC = 14;
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java
new file mode 100644
index 0000000..e269583
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/ElasticOutCurve.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Provide a bouncing Easing function
+ */
+public class ElasticOutCurve extends Easing {
+ private static final float F_PI = (float) Math.PI;
+ private static final float C4 = 2 * F_PI / 3;
+ private static final float TWENTY_PI = 20 * F_PI;
+ private static final float LOG_8 = (float) Math.log(8.0f);
+
+ @Override
+ public float get(float x) {
+ if (x <= 0) {
+ return 0.0f;
+ }
+ if (x >= 1) {
+ return 1.0f;
+ } else
+ return (float) (Math.pow(2.0f, -10 * x)
+ * Math.sin((x * 10 - 0.75f) * C4) + 1);
+ }
+
+ @Override
+ public float getDiff(float x) {
+ if (x < 0 || x > 1) {
+ return 0.0f;
+ } else
+ return (float) ((5 * Math.pow(2.0f, (1 - 10 * x))
+ * (LOG_8 * Math.cos(TWENTY_PI * x / 3) + 2
+ * F_PI * Math.sin(TWENTY_PI * x / 3))
+ / 3));
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
new file mode 100644
index 0000000..4f484de
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/FloatAnimation.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Support Animation of the FloatExpression
+ */
+public class FloatAnimation extends Easing {
+ float[] mSpec;
+ // mSpec[0] = duration
+ // int(mSpec[1]) = num_of_param << 16 | type
+ // mSpec[2..1+num_of_param] params
+ // mSpec[2+num_of_param] starting Value
+ Easing mEasingCurve;
+ private int mType = CUBIC_STANDARD;
+ private float mDuration = 1;
+ private float mWrap = Float.NaN;
+ private float mInitialValue = Float.NaN;
+ private float mTargetValue = Float.NaN;
+ private float mScale = 1;
+ float mOffset = 0;
+
+ @Override
+ public String toString() {
+
+ String str = "type " + mType;
+ if (!Float.isNaN(mInitialValue)) {
+ str += " " + mInitialValue;
+ }
+ if (!Float.isNaN(mTargetValue)) {
+ str += " -> " + mTargetValue;
+ }
+ if (!Float.isNaN(mWrap)) {
+ str += " % " + mWrap;
+ }
+
+ return str;
+ }
+
+ public FloatAnimation() {
+ }
+
+ public FloatAnimation(float... description) {
+ setAnimationDescription(description);
+ }
+
+ public FloatAnimation(int type,
+ float duration,
+ float[] description,
+ float initialValue,
+ float wrap) {
+ setAnimationDescription(packToFloatArray(duration,
+ type, description, initialValue, wrap));
+ }
+
+ /**
+ * packs spec into a float array
+ *
+ * @param duration
+ * @param type
+ * @param spec
+ * @param initialValue
+ * @return
+ */
+ public static float[] packToFloatArray(float duration,
+ int type,
+ float[] spec,
+ float initialValue,
+ float wrap) {
+ int count = 0;
+
+ if (!Float.isNaN(initialValue)) {
+ count++;
+ }
+ if (spec != null) {
+ count++;
+ }
+ if (spec != null || type != CUBIC_STANDARD) {
+ count++;
+ count += (spec == null) ? 0 : spec.length;
+ }
+ if (duration != 1 || count > 0) {
+ count++;
+ }
+ if (!Float.isNaN(initialValue)) {
+ count++;
+ }
+ if (!Float.isNaN(wrap)) {
+ count++;
+ }
+ float[] ret = new float[count];
+ int pos = 0;
+ int specLen = (spec == null) ? 0 : spec.length;
+
+ if (ret.length > 0) {
+ ret[pos++] = duration;
+
+ }
+ if (ret.length > 1) {
+ int wrapBit = (Float.isNaN(wrap)) ? 0 : 1;
+ int initBit = (Float.isNaN(initialValue)) ? 0 : 2;
+ int bits = type | ((wrapBit | initBit) << 8);
+ ret[pos++] = Float.intBitsToFloat(specLen << 16 | bits);
+ }
+
+ if (specLen > 0) {
+ System.arraycopy(spec, 0, ret, pos, spec.length);
+ pos += spec.length;
+ }
+ if (!Float.isNaN(initialValue)) {
+ ret[pos++] = initialValue;
+ }
+ if (!Float.isNaN(wrap)) {
+ ret[pos] = wrap;
+ }
+ return ret;
+ }
+
+ /**
+ * Create an animation based on a float encoding of the animation
+ * @param description
+ */
+ public void setAnimationDescription(float[] description) {
+ mSpec = description;
+ mDuration = (mSpec.length == 0) ? 1 : mSpec[0];
+ int len = 0;
+ if (mSpec.length > 1) {
+ int num_type = Float.floatToRawIntBits(mSpec[1]);
+ mType = num_type & 0xFF;
+ boolean wrap = ((num_type >> 8) & 0x1) > 0;
+ boolean init = ((num_type >> 8) & 0x2) > 0;
+ len = (num_type >> 16) & 0xFFFF;
+ int off = 2 + len;
+ if (init) {
+ mInitialValue = mSpec[off++];
+ }
+ if (wrap) {
+ mWrap = mSpec[off];
+ }
+ }
+ create(mType, description, 2, len);
+ }
+
+ private void create(int type, float[] params, int offset, int len) {
+ switch (type) {
+ case CUBIC_STANDARD:
+ case CUBIC_ACCELERATE:
+ case CUBIC_DECELERATE:
+ case CUBIC_LINEAR:
+ case CUBIC_ANTICIPATE:
+ case CUBIC_OVERSHOOT:
+ mEasingCurve = new CubicEasing(type);
+ break;
+ case CUBIC_CUSTOM:
+ mEasingCurve = new CubicEasing(params[offset + 0],
+ params[offset + 1],
+ params[offset + 2],
+ params[offset + 3]
+ );
+ break;
+ case EASE_OUT_BOUNCE:
+ mEasingCurve = new BounceCurve(type);
+ break;
+ case EASE_OUT_ELASTIC:
+ mEasingCurve = new ElasticOutCurve();
+ break;
+ case SPLINE_CUSTOM:
+ mEasingCurve = new StepCurve(params, offset, len);
+ break;
+ }
+ }
+
+ /**
+ * Get the duration the interpolate is to take
+ * @return duration in seconds
+ */
+ public float getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Set the initial Value
+ * @param value
+ */
+ public void setInitialValue(float value) {
+
+ if (Float.isNaN(mWrap)) {
+ mInitialValue = value;
+ } else {
+ mInitialValue = value % mWrap;
+ }
+ setScaleOffset();
+ }
+
+ /**
+ * Set the target value to interpolate to
+ * @param value
+ */
+ public void setTargetValue(float value) {
+ if (Float.isNaN(mWrap)) {
+ mTargetValue = value;
+ } else {
+ if (Math.abs((value % mWrap) + mWrap - mInitialValue)
+ < Math.abs((value % mWrap) - mInitialValue)) {
+ mTargetValue = (value % mWrap) + mWrap;
+
+ } else {
+ mTargetValue = value % mWrap;
+ }
+ }
+ setScaleOffset();
+ }
+
+ public float getTargetValue() {
+ return mTargetValue;
+ }
+
+ private void setScaleOffset() {
+ if (!Float.isNaN(mInitialValue) && !Float.isNaN(mTargetValue)) {
+ mScale = (mTargetValue - mInitialValue);
+ mOffset = mInitialValue;
+ } else {
+ mScale = 1;
+ mOffset = 0;
+ }
+ }
+
+ /**
+ * get the value at time t in seconds since start
+ */
+ public float get(float t) {
+ return mEasingCurve.get(t / mDuration)
+ * (mTargetValue - mInitialValue) + mInitialValue;
+ }
+
+ /**
+ * get the slope of the easing function at at x
+ */
+ public float getDiff(float t) {
+ return mEasingCurve.getDiff(t / mDuration) * (mTargetValue - mInitialValue);
+ }
+
+ public float getInitialValue() {
+ return mInitialValue;
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
new file mode 100644
index 0000000..693deaf
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/GeneralEasing.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+/**
+ * Provides and interface to create easing functions
+ */
+public class GeneralEasing extends Easing{
+ float[] mEasingData = new float[0];
+ Easing mEasingCurve = new CubicEasing(CUBIC_STANDARD);
+
+ /**
+ * Set the curve based on the float encoding of it
+ * @param data
+ */
+ public void setCurveSpecification(float[] data) {
+ mEasingData = data;
+ createEngine();
+ }
+
+ public float[] getCurveSpecification() {
+ return mEasingData;
+ }
+
+ void createEngine() {
+ int type = Float.floatToRawIntBits(mEasingData[0]);
+ switch (type) {
+ case CUBIC_STANDARD:
+ case CUBIC_ACCELERATE:
+ case CUBIC_DECELERATE:
+ case CUBIC_LINEAR:
+ case CUBIC_ANTICIPATE:
+ case CUBIC_OVERSHOOT:
+ mEasingCurve = new CubicEasing(type);
+ break;
+ case CUBIC_CUSTOM:
+ mEasingCurve = new CubicEasing(mEasingData[1],
+ mEasingData[2],
+ mEasingData[3],
+ mEasingData[5]
+ );
+ break;
+ case EASE_OUT_BOUNCE:
+ mEasingCurve = new BounceCurve(type);
+ break;
+ }
+ }
+
+ /**
+ * get the value at point x
+ */
+ public float get(float x) {
+ return mEasingCurve.get(x);
+ }
+
+ /**
+ * get the slope of the easing function at at x
+ */
+ public float getDiff(float x) {
+ return mEasingCurve.getDiff(x);
+ }
+
+ public int getType() {
+ return mEasingCurve.getType();
+ }
+
+
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
new file mode 100644
index 0000000..23930b9
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/MonotonicCurveFit.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+import java.util.Arrays;
+
+/**
+ * This performs a spline interpolation in multiple dimensions
+ *
+ *
+ */
+public class MonotonicCurveFit {
+ private static final String TAG = "MonotonicCurveFit";
+ private double[] mT;
+ private double[][] mY;
+ private double[][] mTangent;
+ private boolean mExtrapolate = true;
+ double[] mSlopeTemp;
+
+ /**
+ * create a collection of curves
+ * @param time the point along the curve
+ * @param y the parameter at those points
+ */
+ public MonotonicCurveFit(double[] time, double[][] y) {
+ final int n = time.length;
+ final int dim = y[0].length;
+ mSlopeTemp = new double[dim];
+ double[][] slope = new double[n - 1][dim]; // could optimize this out
+ double[][] tangent = new double[n][dim];
+ for (int j = 0; j < dim; j++) {
+ for (int i = 0; i < n - 1; i++) {
+ double dt = time[i + 1] - time[i];
+ slope[i][j] = (y[i + 1][j] - y[i][j]) / dt;
+ if (i == 0) {
+ tangent[i][j] = slope[i][j];
+ } else {
+ tangent[i][j] = (slope[i - 1][j] + slope[i][j]) * 0.5f;
+ }
+ }
+ tangent[n - 1][j] = slope[n - 2][j];
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ for (int j = 0; j < dim; j++) {
+ if (slope[i][j] == 0.) {
+ tangent[i][j] = 0.;
+ tangent[i + 1][j] = 0.;
+ } else {
+ double a = tangent[i][j] / slope[i][j];
+ double b = tangent[i + 1][j] / slope[i][j];
+ double h = Math.hypot(a, b);
+ if (h > 9.0) {
+ double t = 3. / h;
+ tangent[i][j] = t * a * slope[i][j];
+ tangent[i + 1][j] = t * b * slope[i][j];
+ }
+ }
+ }
+ }
+ mT = time;
+ mY = y;
+ mTangent = tangent;
+ }
+
+ /**
+ * Get the position of all curves at time t
+ * @param t
+ * @param v
+ */
+ public void getPos(double t, double[] v) {
+ final int n = mT.length;
+ final int dim = mY[0].length;
+ if (mExtrapolate) {
+ if (t <= mT[0]) {
+ getSlope(mT[0], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[0][j] + (t - mT[0]) * mSlopeTemp[j];
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ getSlope(mT[n - 1], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[n - 1][j] + (t - mT[n - 1]) * mSlopeTemp[j];
+ }
+ return;
+ }
+ } else {
+ if (t <= mT[0]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[0][j];
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[n - 1][j];
+ }
+ return;
+ }
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t == mT[i]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = mY[i][j];
+ }
+ }
+ if (t < mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ for (int j = 0; j < dim; j++) {
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ v[j] = interpolate(h, x, y1, y2, t1, t2);
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Get the position of all curves at time t
+ * @param t
+ * @param v
+ */
+ public void getPos(double t, float[] v) {
+ final int n = mT.length;
+ final int dim = mY[0].length;
+ if (mExtrapolate) {
+ if (t <= mT[0]) {
+ getSlope(mT[0], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) (mY[0][j] + (t - mT[0]) * mSlopeTemp[j]);
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ getSlope(mT[n - 1], mSlopeTemp);
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) (mY[n - 1][j] + (t - mT[n - 1]) * mSlopeTemp[j]);
+ }
+ return;
+ }
+ } else {
+ if (t <= mT[0]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) mY[0][j];
+ }
+ return;
+ }
+ if (t >= mT[n - 1]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) mY[n - 1][j];
+ }
+ return;
+ }
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t == mT[i]) {
+ for (int j = 0; j < dim; j++) {
+ v[j] = (float) mY[i][j];
+ }
+ }
+ if (t < mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ for (int j = 0; j < dim; j++) {
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ v[j] = (float) interpolate(h, x, y1, y2, t1, t2);
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Get the position of the jth curve at time t
+ * @param t
+ * @param j
+ * @return
+ */
+ public double getPos(double t, int j) {
+ final int n = mT.length;
+ if (mExtrapolate) {
+ if (t <= mT[0]) {
+ return mY[0][j] + (t - mT[0]) * getSlope(mT[0], j);
+ }
+ if (t >= mT[n - 1]) {
+ return mY[n - 1][j] + (t - mT[n - 1]) * getSlope(mT[n - 1], j);
+ }
+ } else {
+ if (t <= mT[0]) {
+ return mY[0][j];
+ }
+ if (t >= mT[n - 1]) {
+ return mY[n - 1][j];
+ }
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t == mT[i]) {
+ return mY[i][j];
+ }
+ if (t < mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ return interpolate(h, x, y1, y2, t1, t2);
+
+ }
+ }
+ return 0; // should never reach here
+ }
+
+ /**
+ * Get the slope of all the curves at position t
+ * @param t
+ * @param v
+ */
+ public void getSlope(double t, double[] v) {
+ final int n = mT.length;
+ int dim = mY[0].length;
+ if (t <= mT[0]) {
+ t = mT[0];
+ } else if (t >= mT[n - 1]) {
+ t = mT[n - 1];
+ }
+
+ for (int i = 0; i < n - 1; i++) {
+ if (t <= mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ for (int j = 0; j < dim; j++) {
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ v[j] = diff(h, x, y1, y2, t1, t2) / h;
+ }
+ break;
+ }
+ }
+ return;
+ }
+
+ /**
+ * Get the slope of the j curve at position t
+ * @param t
+ * @param j
+ * @return
+ */
+ public double getSlope(double t, int j) {
+ final int n = mT.length;
+
+ if (t < mT[0]) {
+ t = mT[0];
+ } else if (t >= mT[n - 1]) {
+ t = mT[n - 1];
+ }
+ for (int i = 0; i < n - 1; i++) {
+ if (t <= mT[i + 1]) {
+ double h = mT[i + 1] - mT[i];
+ double x = (t - mT[i]) / h;
+ double y1 = mY[i][j];
+ double y2 = mY[i + 1][j];
+ double t1 = mTangent[i][j];
+ double t2 = mTangent[i + 1][j];
+ return diff(h, x, y1, y2, t1, t2) / h;
+ }
+ }
+ return 0; // should never reach here
+ }
+
+ public double[] getTimePoints() {
+ return mT;
+ }
+
+ /**
+ * Cubic Hermite spline
+ */
+ private static double interpolate(double h,
+ double x,
+ double y1,
+ double y2,
+ double t1,
+ double t2) {
+ double x2 = x * x;
+ double x3 = x2 * x;
+ return -2 * x3 * y2 + 3 * x2 * y2 + 2 * x3 * y1 - 3 * x2 * y1 + y1
+ + h * t2 * x3 + h * t1 * x3 - h * t2 * x2 - 2 * h * t1 * x2
+ + h * t1 * x;
+ }
+
+ /**
+ * Cubic Hermite spline slope differentiated
+ */
+ private static double diff(double h, double x, double y1, double y2, double t1, double t2) {
+ double x2 = x * x;
+ return -6 * x2 * y2 + 6 * x * y2 + 6 * x2 * y1 - 6 * x * y1 + 3 * h * t2 * x2
+ + 3 * h * t1 * x2 - 2 * h * t2 * x - 4 * h * t1 * x + h * t1;
+ }
+
+ /**
+ * This builds a monotonic spline to be used as a wave function
+ */
+ public static MonotonicCurveFit buildWave(String configString) {
+ // done this way for efficiency
+ String str = configString;
+ double[] values = new double[str.length() / 2];
+ int start = configString.indexOf('(') + 1;
+ int off1 = configString.indexOf(',', start);
+ int count = 0;
+ while (off1 != -1) {
+ String tmp = configString.substring(start, off1).trim();
+ values[count++] = Double.parseDouble(tmp);
+ off1 = configString.indexOf(',', start = off1 + 1);
+ }
+ off1 = configString.indexOf(')', start);
+ String tmp = configString.substring(start, off1).trim();
+ values[count++] = Double.parseDouble(tmp);
+
+ return buildWave(Arrays.copyOf(values, count));
+ }
+
+ private static MonotonicCurveFit buildWave(double[] values) {
+ int length = values.length * 3 - 2;
+ int len = values.length - 1;
+ double gap = 1.0 / len;
+ double[][] points = new double[length][1];
+ double[] time = new double[length];
+ for (int i = 0; i < values.length; i++) {
+ double v = values[i];
+ points[i + len][0] = v;
+ time[i + len] = i * gap;
+ if (i > 0) {
+ points[i + len * 2][0] = v + 1;
+ time[i + len * 2] = i * gap + 1;
+
+ points[i - 1][0] = v - 1 - gap;
+ time[i - 1] = i * gap + -1 - gap;
+ }
+ }
+
+ return new MonotonicCurveFit(time, points);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
new file mode 100644
index 0000000..6ed6548
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/utilities/easing/StepCurve.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.widget.remotecompose.core.operations.utilities.easing;
+
+
+/**
+ * This class translates a series of floating point values into a continuous
+ * curve for use in an easing function including quantize functions
+ * it is used with the "spline(0,0.3,0.3,0.5,...0.9,1)" it should start at 0 and end at one 1
+ */
+public class StepCurve extends Easing {
+ private static final boolean DEBUG = false;
+ MonotonicCurveFit mCurveFit;
+
+ public StepCurve(float[] params, int offset, int len) {
+ mCurveFit = genSpline(params, offset, len);
+ }
+
+ private static MonotonicCurveFit genSpline(float[] values, int off, int arrayLen) {
+ int length = arrayLen * 3 - 2;
+ int len = arrayLen - 1;
+ double gap = 1.0 / len;
+ double[][] points = new double[length][1];
+ double[] time = new double[length];
+ for (int i = 0; i < arrayLen; i++) {
+ double v = values[i + off];
+ points[i + len][0] = v;
+ time[i + len] = i * gap;
+ if (i > 0) {
+ points[i + len * 2][0] = v + 1;
+ time[i + len * 2] = i * gap + 1;
+
+ points[i - 1][0] = v - 1 - gap;
+ time[i - 1] = i * gap + -1 - gap;
+ }
+ }
+
+ MonotonicCurveFit ms = new MonotonicCurveFit(time, points);
+
+ return ms;
+ }
+
+ @Override
+ public float getDiff(float x) {
+ return (float) mCurveFit.getSlope(x, 0);
+ }
+
+
+ @Override
+ public float get(float x) {
+ return (float) mCurveFit.getPos(x, 0);
+ }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
index bcda27a..d1c4d46 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposeDocument.java
@@ -79,6 +79,15 @@
}
/**
+ * The delay in milliseconds to next repaint -1 = not needed 0 = asap
+ *
+ * @return delay in milliseconds to next repaint or -1
+ */
+ public int needsRepaint() {
+ return mDocument.needsRepaint();
+ }
+
+ /**
* Returns true if the document can be displayed given this version of the player
*
* @param majorVersion the max major version supported by the player
@@ -89,5 +98,10 @@
return mDocument.canBeDisplayed(majorVersion, minorVersion, capabilities);
}
+ @Override
+ public String toString() {
+ return "Document{\n"
+ + mDocument + '}';
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index d0d6e69..ecb68bb 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -26,6 +26,7 @@
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.RuntimeShader;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.Typeface;
@@ -33,6 +34,8 @@
import com.android.internal.widget.remotecompose.core.PaintContext;
import com.android.internal.widget.remotecompose.core.RemoteContext;
import com.android.internal.widget.remotecompose.core.operations.ClipPath;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
+import com.android.internal.widget.remotecompose.core.operations.Utils;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle;
import com.android.internal.widget.remotecompose.core.operations.paint.PaintChanges;
@@ -43,6 +46,7 @@
public class AndroidPaintContext extends PaintContext {
Paint mPaint = new Paint();
Canvas mCanvas;
+ Rect mTmpRect = new Rect(); // use in calculation of bounds
public AndroidPaintContext(RemoteContext context, Canvas canvas) {
super(context);
@@ -177,6 +181,22 @@
}
@Override
+ public void getTextBounds(int textId, int start, int end, boolean monospace, float[] bounds) {
+ String str = getText(textId);
+ if (end == -1) {
+ end = str.length();
+ }
+
+ mPaint.getTextBounds(str, start, end, mTmpRect);
+
+ bounds[0] = mTmpRect.left;
+ bounds[1] = mTmpRect.top;
+ bounds[2] = monospace ? (mPaint.measureText(str, start, end) - mTmpRect.left)
+ : mTmpRect.right;
+ bounds[3] = mTmpRect.bottom;
+ }
+
+ @Override
public void drawTextRun(int textID,
int start,
int end,
@@ -185,7 +205,16 @@
float x,
float y,
boolean rtl) {
- String textToPaint = getText(textID).substring(start, end);
+
+ String textToPaint = getText(textID);
+ if (end == -1) {
+ if (start != 0) {
+ textToPaint = textToPaint.substring(start);
+ }
+ } else {
+ textToPaint = textToPaint.substring(start, end);
+ }
+
mCanvas.drawText(textToPaint, x, y, mPaint);
}
@@ -308,7 +337,7 @@
@Override
public void applyPaint(PaintBundle mPaintData) {
- mPaintData.applyPaintChange(new PaintChanges() {
+ mPaintData.applyPaintChange((PaintContext) this, new PaintChanges() {
@Override
public void setTextSize(float size) {
mPaint.setTextSize(size);
@@ -361,10 +390,8 @@
}
}
-
}
-
@Override
public void setStrokeWidth(float width) {
mPaint.setStrokeWidth(width);
@@ -386,13 +413,37 @@
}
@Override
- public void setShader(int shader, String shaderString) {
-
+ public void setShader(int shaderId) {
+ // TODO this stuff should check the shader creation
+ if (shaderId == 0) {
+ mPaint.setShader(null);
+ return;
+ }
+ ShaderData data = getShaderData(shaderId);
+ RuntimeShader shader = new RuntimeShader(getText(data.getShaderTextId()));
+ String[] names = data.getUniformFloatNames();
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ float[] val = data.getUniformFloats(name);
+ shader.setFloatUniform(name, val);
+ }
+ names = data.getUniformIntegerNames();
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ int[] val = data.getUniformInts(name);
+ shader.setIntUniform(name, val);
+ }
+ names = data.getUniformBitmapNames();
+ for (int i = 0; i < names.length; i++) {
+ String name = names[i];
+ int val = data.getUniformBitmapId(name);
+ }
+ mPaint.setShader(shader);
}
@Override
public void setImageFilterQuality(int quality) {
- System.out.println(">>>>>>>>>>>> ");
+ Utils.log(" quality =" + quality);
}
@Override
@@ -420,7 +471,6 @@
mPaint.setFilterBitmap(filter);
}
-
@Override
public void setAntiAlias(boolean aa) {
mPaint.setAntiAlias(aa);
@@ -437,7 +487,6 @@
case PaintBundle.COLOR_FILTER:
mPaint.setColorFilter(null);
- System.out.println(">>>>>>>>>>>>> CLEAR!!!!");
break;
}
}
@@ -446,12 +495,11 @@
}
}
- Shader.TileMode[] mTilesModes = new Shader.TileMode[]{
+ Shader.TileMode[] mTileModes = new Shader.TileMode[]{
Shader.TileMode.CLAMP,
Shader.TileMode.REPEAT,
Shader.TileMode.MIRROR};
-
@Override
public void setLinearGradient(int[] colors,
float[] stops,
@@ -463,7 +511,7 @@
mPaint.setShader(new LinearGradient(startX,
startY,
endX,
- endY, colors, stops, mTilesModes[tileMode]));
+ endY, colors, stops, mTileModes[tileMode]));
}
@@ -475,7 +523,7 @@
float radius,
int tileMode) {
mPaint.setShader(new RadialGradient(centerX, centerY, radius,
- colors, stops, mTilesModes[tileMode]));
+ colors, stops, mTileModes[tileMode]));
}
@Override
@@ -490,7 +538,6 @@
@Override
public void setColorFilter(int color, int mode) {
PorterDuff.Mode pmode = origamiToPorterDuffMode(mode);
- System.out.println("setting color filter to " + pmode.name());
if (pmode != null) {
mPaint.setColorFilter(
new PorterDuffColorFilter(color, pmode));
@@ -500,10 +547,10 @@
}
@Override
- public void mtrixScale(float scaleX,
- float scaleY,
- float centerX,
- float centerY) {
+ public void matrixScale(float scaleX,
+ float scaleY,
+ float centerX,
+ float centerY) {
if (Float.isNaN(centerX)) {
mCanvas.scale(scaleX, scaleY);
} else {
@@ -556,6 +603,11 @@
}
}
+ @Override
+ public void reset() {
+ mPaint.reset();
+ }
+
private Path getPath(int path1Id,
int path2Id,
float tween,
@@ -599,5 +651,9 @@
private String getText(int id) {
return (String) mContext.mRemoteComposeState.getFromId(id);
}
+
+ private ShaderData getShaderData(int id) {
+ return (ShaderData) mContext.mRemoteComposeState.getFromId(id);
+ }
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
index 270e96f..6e4893b 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java
@@ -20,10 +20,15 @@
import android.graphics.Canvas;
import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
+import com.android.internal.widget.remotecompose.core.operations.FloatExpression;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
+
+import java.util.HashMap;
/**
* An implementation of Context for Android.
- *
+ * <p>
* This is used to play the RemoteCompose operations on Android.
*/
class AndroidRemoteContext extends RemoteContext {
@@ -33,6 +38,7 @@
mPaintContext = new AndroidPaintContext(this, canvas);
} else {
// need to make sure to update the canvas for the current one
+ mPaintContext.reset();
((AndroidPaintContext) mPaintContext).setCanvas(canvas);
}
mWidth = canvas.getWidth();
@@ -50,13 +56,32 @@
}
}
+ static class VarName {
+ String mName;
+ int mId;
+ int mType;
+
+ VarName(String name, int id, int type) {
+ mName = name;
+ mId = id;
+ mType = type;
+ }
+ }
+
+ HashMap<String, VarName> mVarNameHashMap = new HashMap<>();
+
+ @Override
+ public void loadVariableName(String varName, int varId, int varType) {
+ mVarNameHashMap.put(varName, new VarName(varName, varId, varType));
+ }
+
/**
* Decode a byte array into an image and cache it using the given imageId
*
- * @oaram imageId the id of the image
- * @param width with of image to be loaded
+ * @param width with of image to be loaded
* @param height height of image to be loaded
* @param bitmap a byte array containing the image information
+ * @oaram imageId the id of the image
*/
@Override
public void loadBitmap(int imageId, int width, int height, byte[] bitmap) {
@@ -70,14 +95,66 @@
public void loadText(int id, String text) {
if (!mRemoteComposeState.containsId(id)) {
mRemoteComposeState.cache(id, text);
+ } else {
+ mRemoteComposeState.update(id, text);
}
}
+ @Override
+ public String getText(int id) {
+ return (String) mRemoteComposeState.getFromId(id);
+ }
+
+ @Override
+ public void loadFloat(int id, float value) {
+ mRemoteComposeState.updateFloat(id, value);
+ }
+
+
+ @Override
+ public void loadColor(int id, int color) {
+ mRemoteComposeState.updateColor(id, color);
+ }
+
+ @Override
+ public void loadAnimatedFloat(int id, FloatExpression animatedFloat) {
+ mRemoteComposeState.cache(id, animatedFloat);
+ }
+
+ @Override
+ public void loadShader(int id, ShaderData value) {
+ mRemoteComposeState.cache(id, value);
+ }
+
+ @Override
+ public float getFloat(int id) {
+ return (float) mRemoteComposeState.getFloat(id);
+ }
+
+ @Override
+ public int getColor(int id) {
+ return mRemoteComposeState.getColor(id);
+ }
+
+ @Override
+ public void listensTo(int id, VariableSupport variableSupport) {
+ mRemoteComposeState.listenToVar(id, variableSupport);
+ }
+
+ @Override
+ public int updateOps() {
+ return mRemoteComposeState.getOpsToUpdate(this);
+ }
+
+ @Override
+ public ShaderData getShader(int id) {
+ return (ShaderData) mRemoteComposeState.getFromId(id);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////
// Click handling
///////////////////////////////////////////////////////////////////////////////////////////////
-
@Override
public void addClickArea(int id,
int contentDescriptionId,
@@ -87,7 +164,7 @@
float bottom,
int metadataId) {
String contentDescription = (String) mRemoteComposeState.getFromId(contentDescriptionId);
- String metadata = (String) mRemoteComposeState.getFromId(metadataId);
+ String metadata = (String) mRemoteComposeState.getFromId(metadataId);
mDocument.addClickArea(id, contentDescription, left, top, right, bottom, metadata);
}
}
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
index 672dae3..329178a 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/ClickAreaView.java
@@ -20,7 +20,6 @@
import android.graphics.Paint;
import android.view.View;
-
/**
* Implementation for the click handling
*/
@@ -40,7 +39,6 @@
setContentDescription(contentDescription);
}
-
public void setDebug(boolean value) {
if (mDebug != value) {
mDebug = value;
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index a3bb73e..97d23c8 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -85,6 +85,7 @@
mDocument.initializeContext(mARContext);
setContentDescription(mDocument.getDocument().getContentDescription());
requestLayout();
+ invalidate();
}
AndroidRemoteContext mARContext = new AndroidRemoteContext();
@@ -119,8 +120,7 @@
removeAllViews();
}
-
- public interface ClickCallbacks {
+ public interface ClickCallbacks {
void click(int id, String metadata);
}
@@ -213,6 +213,9 @@
setMeasuredDimension(w, h);
}
+ private int mCount;
+ private long mTime = System.nanoTime();
+
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
@@ -224,6 +227,17 @@
mARContext.mWidth = getWidth();
mARContext.mHeight = getHeight();
mDocument.paint(mARContext, mTheme);
+ if (mDebug) {
+ mCount++;
+ if (System.nanoTime() - mTime > 1000000000L) {
+ System.out.println(" count " + mCount + " fps");
+ mCount = 0;
+ mTime = System.nanoTime();
+ }
+ }
+ if (mDocument.needsRepaint() > 0) {
+ invalidate();
+ }
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index e831a7d..5365838 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -358,7 +358,8 @@
jobject stats =
env->NewObject(gTransactionStatsClassInfo.clazz, gTransactionStatsClassInfo.ctor,
- latchTime, presentFence.get());
+ latchTime,
+ static_cast<jlong>(reinterpret_cast<uintptr_t>(presentFence.get())));
env->CallVoidMethod(mTransactionCompletedListenerObject, gConsumerClassInfo.accept, stats);
env->DeleteLocalRef(stats);
DieIfException(env, "Uncaught exception in TransactionCompletedListener.");
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index 1233069..6a0ec1d 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -126,6 +126,7 @@
option (android.msg_privacy).dest = DEST_EXPLICIT;
optional SettingProto pointer_fill_style = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto pointer_scale = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Pointer pointer = 37;
optional SettingProto pointer_speed = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 09ffdf3..c71f9bd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3249,16 +3249,20 @@
<permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
android:protectionLevel="signature|appop" />
- <!-- Allows applications to access profiles with ACCESS_HIDDEN_PROFILES user property
- <p>Protection level: normal
- @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") -->
+ <!-- Allows applications to access profiles with
+ {@code android.content.pm.UserProperties#PROFILE_API_VISIBILITY_HIDDEN} user property, e.g.
+ {@link android.os.UserManager#USER_TYPE_PROFILE_PRIVATE}.
+ <p>Protection level: normal
+ @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") -->
<permission android:name="android.permission.ACCESS_HIDDEN_PROFILES"
android:label="@string/permlab_accessHiddenProfile"
android:description="@string/permdesc_accessHiddenProfile"
android:protectionLevel="normal" />
- <!-- @SystemApi @hide Allows privileged applications to get details about hidden profile
- users.
+ <!-- @SystemApi @hide Allows privileged applications to get details about profiles with
+ {@code android.content.pm.UserProperties#PROFILE_API_VISIBILITY_HIDDEN} user property, e.g.
+ {@link android.os.UserManager#USER_TYPE_PROFILE_PRIVATE}. Removes extra requirements such
+ as having {@link android.app.role.RoleManager#ROLE_HOME} role for LauncherApps APIs.
@FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") -->
<permission
android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL"
@@ -3322,13 +3326,18 @@
<!-- Allows an application to manage device policy relating to time.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
- APIs protected by this permission on users different to the calling user.-->
+ APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_TIME"
android:protectionLevel="internal|role" />
<!-- Allows an application to set the grant state of runtime permissions on packages.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS"
android:protectionLevel="internal|role" />
@@ -3336,6 +3345,8 @@
<!-- Allows an application to manage the identity of the managing organization.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY"
android:protectionLevel="internal|role" />
@@ -3344,6 +3355,8 @@
active policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE"
android:protectionLevel="internal|role" />
@@ -3351,6 +3364,8 @@
<!-- Allows an application to manage backup service policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BACKUP_SERVICE"
android:protectionLevel="internal|role" />
@@ -3358,6 +3373,8 @@
<!-- Allows an application to manage lock task policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK"
android:protectionLevel="internal|role" />
@@ -3365,6 +3382,8 @@
<!-- Allows an application to manage policy regarding modifying applications.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"
android:protectionLevel="internal|role" />
@@ -3372,6 +3391,8 @@
<!-- Allows an application to manage installing from unknown sources policy.
<p>MANAGE_SECURITY_CRITICAL_DEVICE_POLICY_ACROSS_USERS is required to call APIs protected
by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES"
android:protectionLevel="internal|role" />
@@ -3379,6 +3400,8 @@
<!-- Allows an application to manage application restrictions.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_RESTRICTIONS"
android:protectionLevel="internal|role" />
@@ -3386,6 +3409,8 @@
<!-- Allows an application to manage calling policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CALLS"
android:protectionLevel="internal|role" />
@@ -3393,6 +3418,8 @@
<!-- Allows an application to manage debugging features policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES"
android:protectionLevel="internal|role" />
@@ -3400,6 +3427,8 @@
<!-- Allows an application to manage policy preventing users from modifying users.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MODIFY_USERS"
android:protectionLevel="internal|role" />
@@ -3407,6 +3436,8 @@
<!-- Allows an application to manage safe boot policy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SAFE_BOOT"
android:protectionLevel="internal|role" />
@@ -3415,6 +3446,8 @@
enable and disable the microphone.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE"
android:protectionLevel="internal|role" />
@@ -3423,6 +3456,8 @@
enable and disable the camera.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA"
android:protectionLevel="internal|role" />
@@ -3430,6 +3465,8 @@
<!-- Allows an application to manage policy related to keyguard.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"
android:protectionLevel="internal|role" />
@@ -3437,6 +3474,8 @@
<!-- Allows an application to set policy related to account management.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT"
android:protectionLevel="internal|role" />
@@ -3444,6 +3483,8 @@
<!-- Allows an application to set policy related to hiding and suspending packages.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PACKAGE_STATE"
android:protectionLevel="internal|role" />
@@ -3452,17 +3493,24 @@
challenge on current user.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD"
android:protectionLevel="internal|role" />
- <!-- Allows an application to set policy related to the status bar.-->
+ <!-- Allows an application to set policy related to the status bar.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_STATUS_BAR"
android:protectionLevel="internal|role" />
<!-- Allows an application to set policy related to bluetooth.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLUETOOTH"
android:protectionLevel="internal|role" />
@@ -3470,6 +3518,8 @@
<!-- Allows an application to set policy related to fun.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_FUN"
android:protectionLevel="internal|role" />
@@ -3477,6 +3527,8 @@
<!-- Allows an application to set policy related to airplane mode.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_AIRPLANE_MODE"
android:protectionLevel="internal|role" />
@@ -3484,6 +3536,8 @@
<!-- Allows an application to set policy related to mobile networks.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MOBILE_NETWORK"
android:protectionLevel="internal|role" />
@@ -3491,6 +3545,8 @@
<!-- Allows an application to set policy related to physical media.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA"
android:protectionLevel="internal|role" />
@@ -3498,6 +3554,8 @@
<!-- Allows an application to set policy related to sms.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SMS"
android:protectionLevel="internal|role" />
@@ -3505,6 +3563,8 @@
<!-- Allows an application to set policy related to usb file transfers.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER"
android:protectionLevel="internal|role" />
@@ -3512,6 +3572,8 @@
<!-- Allows an application to set policy related to lock credentials.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS"
android:protectionLevel="internal|role" />
@@ -3519,6 +3581,8 @@
<!-- Allows an application to set policy related to Wifi.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIFI"
android:protectionLevel="internal|role" />
@@ -3526,6 +3590,8 @@
<!-- Allows an application to set policy related to screen capture.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CAPTURE"
android:protectionLevel="internal|role" />
@@ -3533,6 +3599,8 @@
<!-- Allows an application to set policy related to input methods.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS"
android:protectionLevel="internal|role" />
@@ -3541,6 +3609,8 @@
private DNS.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS"
android:protectionLevel="internal|role" />
@@ -3548,6 +3618,8 @@
<!-- Allows an application to set policy related to the default sms application.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS"
android:protectionLevel="internal|role" />
@@ -3555,6 +3627,8 @@
<!-- Allows an application to set policy related to profiles.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILES"
android:protectionLevel="internal|role" />
@@ -3563,6 +3637,8 @@
cross-profile copy and paste).
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION"
android:protectionLevel="internal|role" />
@@ -3570,6 +3646,8 @@
<!-- Allows an application to set policy related to VPNs.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_VPN"
android:protectionLevel="internal|role" />
@@ -3577,6 +3655,8 @@
<!-- Allows an application to set policy related to audio output.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUDIO_OUTPUT"
android:protectionLevel="internal|role" />
@@ -3584,6 +3664,8 @@
<!-- Allows an application to set policy related to the display.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DISPLAY"
android:protectionLevel="internal|role" />
@@ -3591,6 +3673,8 @@
<!-- Allows an application to set policy related to location.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCATION"
android:protectionLevel="internal|role" />
@@ -3598,6 +3682,8 @@
<!-- Allows an application to set policy related to factory reset.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_FACTORY_RESET"
android:protectionLevel="internal|role" />
@@ -3605,6 +3691,8 @@
<!-- Allows an application to set policy related to the wallpaper.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WALLPAPER"
android:protectionLevel="internal|role" />
@@ -3612,6 +3700,8 @@
<!-- Allows an application to set policy related to the usage of the contents of the screen.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SCREEN_CONTENT"
android:protectionLevel="internal|role" />
@@ -3619,6 +3709,8 @@
<!-- Allows an application to set policy related to system dialogs.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS"
android:protectionLevel="internal|role" />
@@ -3626,6 +3718,8 @@
<!-- Allows an application to set policy related to users running in the background.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUN_IN_BACKGROUND"
android:protectionLevel="internal|role" />
@@ -3633,6 +3727,8 @@
<!-- Allows an application to set policy related to printing.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRINTING"
android:protectionLevel="internal|role" />
@@ -3641,12 +3737,16 @@
nearby streaming).
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION"
android:protectionLevel="internal|role" />
<!-- Allows an application to set policy related to <a
href="https://www.threadgroup.org">Thread</a> network.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"
@@ -3654,6 +3754,8 @@
<!-- Allows an application to set policy related to sending assist content to a
privileged app such as the Assistant app.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.assist_content_user_restriction_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ASSIST_CONTENT"
@@ -3662,6 +3764,8 @@
<!-- Allows an application to set policy related to windows.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WINDOWS"
android:protectionLevel="internal|role" />
@@ -3669,6 +3773,8 @@
<!-- Allows an application to set policy related to locale.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCALE"
android:protectionLevel="internal|role" />
@@ -3676,6 +3782,8 @@
<!-- Allows an application to set policy related to autofill.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_AUTOFILL"
android:protectionLevel="internal|role" />
@@ -3683,6 +3791,8 @@
<!-- Allows an application to set policy related to users.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_USERS"
android:protectionLevel="internal|role" />
@@ -3690,6 +3800,8 @@
<!-- Allows an application to set policy related to certificates.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES"
android:protectionLevel="internal|role" />
@@ -3697,6 +3809,8 @@
<!-- Allows an application to set policy related to override APNs.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_OVERRIDE_APN"
android:protectionLevel="internal|role" />
@@ -3704,6 +3818,8 @@
<!-- Allows an application to set policy related to security logging.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SECURITY_LOGGING"
android:protectionLevel="internal|role" />
@@ -3719,6 +3835,8 @@
<!-- Allows an application to set policy related to system updates.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES"
android:protectionLevel="internal|role" />
@@ -3726,6 +3844,8 @@
<!-- Allows an application query system updates.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_QUERY_SYSTEM_UPDATES"
android:protectionLevel="internal|role" />
@@ -3733,6 +3853,8 @@
<!-- Allows an application to set policy related to private DNS.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PRIVATE_DNS"
android:protectionLevel="internal|role" />
@@ -3740,6 +3862,8 @@
<!-- Allows an application to set policy related to settings.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SETTINGS"
android:protectionLevel="internal|role" />
@@ -3747,17 +3871,24 @@
<!-- Allows an application to set policy related to network logging.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_NETWORK_LOGGING"
android:protectionLevel="internal|role" />
- <!-- Allows an application to set policy related to usb data signalling.-->
+ <!-- Allows an application to set policy related to usb data signalling.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING"
android:protectionLevel="internal|role" />
<!-- Allows an application to set policy related to suspending personal apps.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SUSPEND_PERSONAL_APPS"
android:protectionLevel="internal|role" />
@@ -3765,13 +3896,17 @@
<!-- Allows an application to set policy related to keeping uninstalled packages.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is
required to call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEEP_UNINSTALLED_PACKAGES"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to accessibility.
- <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
- APIs protected by this permission on users different to the calling user.
+ <p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to
+ call APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACCESSIBILITY"
android:protectionLevel="internal|role" />
@@ -3779,6 +3914,8 @@
<!-- Allows an application to manage policy related to common criteria mode.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE"
android:protectionLevel="internal|role" />
@@ -3786,6 +3923,8 @@
<!-- Allows an application to manage policy related to metered data.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_METERED_DATA"
android:protectionLevel="internal|role" />
@@ -3793,6 +3932,8 @@
<!-- Allows an application to set a network-independent global HTTP proxy.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROXY"
android:protectionLevel="internal|role" />
@@ -3800,6 +3941,8 @@
<!-- Allows an application to request bugreports with user consent.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BUGREPORT"
android:protectionLevel="internal|role" />
@@ -3807,6 +3950,8 @@
<!-- Allows an application to manage policy related to application user data.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_USER_DATA"
android:protectionLevel="internal|role" />
@@ -3815,6 +3960,8 @@
permission.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK"
android:protectionLevel="internal|role" />
@@ -3830,6 +3977,8 @@
<!-- Allows an application to manage policy related to system apps.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS"
android:protectionLevel="internal|role" />
@@ -3837,16 +3986,23 @@
<!-- Allows an application to manage policy related to wiping data.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS} is required to call
APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to the Memory Tagging Extension (MTE).
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MTE"
android:protectionLevel="internal|role" />
- <!-- Allows an application to manage policy related to device identifiers. -->
+ <!-- Allows an application to manage policy related to device identifiers.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS"
android:protectionLevel="internal|role" />
@@ -3859,24 +4015,33 @@
<!-- Allows an application to set policy related to subscriptions downloaded by an admin.
<p>{@link Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL} is required to call
- APIs protected by this permission on users different to the calling user.
- @FlaggedApi("android.app.admin.flags.esim_management_enabled") -->
+ APIs protected by this permission on users different to the calling user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ @FlaggedApi("android.app.admin.flags.esim_management_enabled")
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MANAGED_SUBSCRIPTIONS"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to block package uninstallation.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_BLOCK_UNINSTALL"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to camera toggle.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_CAMERA_TOGGLE"
android:protectionLevel="internal|role" />
<!-- Allows an application to manage policy related to microphone toggle.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
@FlaggedApi("android.app.admin.flags.dedicated_device_control_api_enabled")
-->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_MICROPHONE_TOGGLE"
@@ -3885,16 +4050,21 @@
<!-- Allows an application to set device policies outside the current user
that are critical for securing data within the current user.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
- permissions across all users on the device provided they are required for securing data
- within the current user.-->
+ permissions across all users on the device provided they are required for securing data
+ within the current user.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL"
android:protectionLevel="internal|role" />
<!-- Allows an application to set device policies outside the current user
that are required for securing device ownership without accessing user data.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
- permissions across all users on the device provided they do not grant access to user
- data. -->
+ permissions across all users on the device provided they do not grant access to user data.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS"
android:protectionLevel="internal|role" />
@@ -3902,7 +4072,10 @@
<p>Fuller form of {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ACROSS_USERS}
that removes the restriction on accessing user data.
<p>Holding this permission allows the use of any other held MANAGE_DEVICE_POLICY_*
- permissions across all users on the device.-->
+ permissions across all users on the device.
+ <p>Protection level: internal|role
+ <p>Intended for use by the DEVICE_POLICY_MANAGEMENT role only.
+ -->
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL"
android:protectionLevel="internal|role" />
@@ -8194,6 +8367,17 @@
<permission android:name="android.permission.SETUP_FSVERITY"
android:protectionLevel="signature|privileged"/>
+ <!--
+ @TestApi
+ Signature permission reserved for testing. This should never be used to
+ gate any actual functionality.
+ <p>
+ Protection level: signature
+ @hide
+ -->
+ <permission android:name="android.permission.RESERVED_FOR_TESTING_SIGNATURE"
+ android:protectionLevel="signature"/>
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 704d442..18425fe 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaat ruimte"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeenskaplik"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privaat ruimte"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitiewe kennisgewinginhoud is versteek"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Appinhoud is weens sekuriteit van skermdeling verberg"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index d1e18da..965160e 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"የግል ቦታ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"አባዛ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"የጋራ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"የግል ቦታ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"አደገኛ የማሳወቂያ ይዘት ተደብቋል"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ለደኅንነት ሲባል የመተግበሪያ ይዘት ከማያ ገጽ ማጋራት ተደብቋል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 5ef18af..3e396e0 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2411,8 +2411,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"المساحة الخاصة"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"نسخة طبق الأصل"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ملف شخصي مشترك"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"المساحة الخاصّة"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"تم إخفاء المحتوى الحساس في الإشعار"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"تم إخفاء محتوى التطبيق بعد تفعيل ميزة \"مشاركة الشاشة\" للحفاظ على أمانك"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 5443f12..5f9f16a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1865,7 +1865,7 @@
<string name="mediasize_japanese_you4" msgid="5552111912684384833">"You4"</string>
<string name="mediasize_japanese_l" msgid="1326765321473431817">"L"</string>
<string name="mediasize_unknown_portrait" msgid="3817016220446495613">"অজ্ঞাত প\'ৰ্ট্ৰেইট"</string>
- <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজ্ঞাত লেণ্ডস্কেইপ"</string>
+ <string name="mediasize_unknown_landscape" msgid="1584741567225095325">"অজ্ঞাত লেণ্ডস্কে’প"</string>
<string name="write_fail_reason_cancelled" msgid="2344081488493969190">"বাতিল কৰা হ’ল"</string>
<string name="write_fail_reason_cannot_write" msgid="432118118378451508">"সমল লিখাত আসোঁৱাহ"</string>
<string name="reason_unknown" msgid="5599739807581133337">"অজ্ঞাত"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্ৰাইভেট স্পে’চ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্ল’ন"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"সম্প্ৰদায়ৰ সৈতে জড়িত"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"প্ৰাইভেট স্পে’চ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল জাননী লুকুওৱা হৈছে"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"সুৰক্ষাৰ বাবে এপৰ সমল স্ক্ৰীণ শ্বেয়াৰ কৰাৰ পৰা লুকুৱাই ৰখা হৈছে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index b9ec742..c4327e7 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Məxfi sahə"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Kommunal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Şəxsi sahə"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Həssas bildiriş kontenti gizlədildi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Güvənlik üçün tətbiq kontenti ekran paylaşımından gizlədildi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 858075b..2b81e1c 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatan prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonirano"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Zajedničko"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privatan prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Osetljiv sadržaj obaveštenja je skriven"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je skriven za deljenje sadržaja ekrana zbog bezbednosti"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2739cb2..7d1f6be 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Прыватная прастора"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Супольны"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Прыватная прастора"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Канфідэнцыяльнае змесціва ў апавяшчэннях схавана"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Змесціва праграмы выключана з абагульвання экрана ў мэтах бяспекі"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0d4cadc..a2f0364 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частно пространство"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониране"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Общи"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Частно пространство"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Деликатното съдържание в известието е скрито"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Съдържанието на приложението е скрито от функцията за споделяне на екрана от съображения за сигурност"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 03fba4b..e21b5c0 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"প্রাইভেট স্পেস"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ক্লোন"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"কমিউনাল"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"প্রাইভেট স্পেস"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"সংবেদনশীল বিজ্ঞপ্তির কন্টেন্ট লুকানো আছে"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"নিরাপত্তার জন্য স্ক্রিন শেয়ার করা থেকে লুকানো অ্যাপের কন্টেন্ট"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 6ce10c0..2f285f1 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Opće"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privatni prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sakriven je osjetljiv sadržaj obavještenja"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije je sakriven od dijeljenja ekrana radi sigurnosti"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4b1af34..48ba090c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espai privat"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comunitari"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espai privat"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"S\'ha amagat contingut sensible de les notificacions"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contingut de l\'aplicació amagat de la compartició de pantalla per motius de seguretat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index cc4bd3c..64ccaf5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Soukromý prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Komunální"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Soukromý prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivých oznámení je skrytý"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikace je z bezpečnostních důvodů při sdílení obrazovky skryt"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 665ea17..a499afc 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Fælles"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privat område"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Følsomt indhold i notifikationen er skjult"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Af sikkerhedsmæssige årsager vises appindhold ikke ved skærmdeling"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index cd637e1..464a5373 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Vertrauliches Profil"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeinsam genutzt"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Vertrauliches Profil"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Vertrauliche Benachrichtigungsinhalte ausgeblendet"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-Inhalte werden aus Sicherheitsgründen bei der Bildschirmfreigabe ausgeblendet"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 09ecc2c..98ce03c 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ιδιωτικός χώρος"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Κλώνος"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Κοινόχρηστο"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Ιδιωτικός χώρος"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Έγινε απόκρυψη της ειδοποίησης ευαίσθητου περιεχομένου"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Για λόγους ασφάλειας, έγινε απόκρυψη του περιεχομένου της εφαρμογής από την κοινή χρήση οθόνης"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 20e391d..1d2fc4d 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 7f33f6a..c03bb3c 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index b7fedbe..436d7ae 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b83a7cf..d34ed3f6e 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index d358e5e..c2c107c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Private space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Private space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitive notification content hidden"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App content hidden from screen share for security"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 45ea7ee..df7deac 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Compartido"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espacio privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Se ocultó contenido sensible de la notificación"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Se ocultó el contenido de la app durante el uso compartido de la pantalla por motivos de seguridad"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 19c5f84..e22430f 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -717,7 +717,7 @@
<string name="face_acquired_too_right" msgid="6245286514593540859">"Mueve el teléfono hacia la izquierda"</string>
<string name="face_acquired_too_left" msgid="9201762240918405486">"Mueve el teléfono hacia la derecha"</string>
<string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Mira de forma más directa al dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se puede detectar tu cara. Sujeta el teléfono a la altura de los ojos."</string>
+ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se detecta tu cara. Sujeta el teléfono a la altura de los ojos."</string>
<string name="face_acquired_too_much_motion" msgid="8199691445085189528">"El teléfono se mueve demasiado. Mantenlo quieto."</string>
<string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu cara."</string>
<string name="face_acquired_too_different" msgid="4505278456634706967">"Cara no reconocida. Inténtalo de nuevo."</string>
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espacio privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Común"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espacio privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Contenido sensible de la notificación oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenido de la aplicación oculto en pantalla compartida por motivos de seguridad"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 46c7341..979079d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privaatne ruum"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Ühine"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privaatne ruum"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Märguande delikaatne sisu peideti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Rakenduse sisu on ekraani jagamises turvalisuse huvides peidetud"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3c47f68..06855f5 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -190,7 +190,7 @@
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"<xliff:g id="CONTENT_TYPE">%s</xliff:g> gehiegi ezabatzen saiatu zara."</string>
<string name="low_memory" product="tablet" msgid="5557552311566179924">"Tabletaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
<string name="low_memory" product="watch" msgid="3479447988234030194">"Erlojuaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
- <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV gailuaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
+ <string name="low_memory" product="tv" msgid="6663680413790323318">"Android TV gailuko biltegia beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
<string name="low_memory" product="default" msgid="2539532364144025569">"Telefonoaren memoria beteta dago. Tokia egiteko, ezabatu fitxategi batzuk."</string>
<string name="ssl_ca_cert_warning" msgid="7233573909730048571">"{count,plural, =1{Autoritate ziurtagiri-emaile bat dago instalatuta}other{Autoritate ziurtagiri-emaile bat baino gehiago daude instalatuta}}"</string>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4961102218216815242">"Hirugarren alderdi ezezagun baten arabera"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Eremu pribatua"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Partekatua"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Eremu pribatua"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Jakinarazpenaren kontuzko edukia ezkutatu da"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Aplikazioko edukia ezkutatu egin da pantaila partekatzeko eginbidetik, segurtasuna bermatzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 3c50b07..b0e6e6e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"فضای خصوصی"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"همسانهسازی"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"همگانی"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"فضای خصوصی"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"محتوای اعلان حساس پنهان شده است"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"بهدلایل امنیتی، محتوای برنامه از دید همرسانی صفحهنمایش پنهان شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 0e159f2..7e2fa9c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Yksityinen tila"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klooni"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Yhteinen"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Yksityinen tila"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Arkaluontoisen ilmoituksen sisältö piilotettu"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sovelluksen sisältö piilotettu näytön jakamiselta turvallisuussyistä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 7fca5e6..a21aefb 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espace privé"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu confidentiel de la notification est masqué"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'application est masqué du Partage d\'écran par mesure de sécurité"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e08f426..486124e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espace privé"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Commun"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espace privé"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Le contenu sensible de la notification a été masqué"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Le contenu de l\'appli est masqué lors du partage d\'écran pour des raisons de sécurité"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 1eec828..9994a3e 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espazo privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonado"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Compartido"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espazo privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Contido confidencial da notificación oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Por motivos de seguranza, ocultouse o contido da aplicación para que no se mostre na pantalla compartida"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 303f001..3206242 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ખાનગી સ્પેસ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ક્લોન"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"કૉમ્યુનલ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ખાનગી સ્પેસ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"સંવેદનશીલ માહિતીવાળા નોટિફિકેશનનું કન્ટેન્ટ છુપાવ્યું"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"સુરક્ષા માટે સ્ક્રીન શેર કરતી વખતે ઍપનું કન્ટેન્ટ છુપાવેલું છે"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 14d2bf7..f7ae13e 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"प्राइवेट स्पेस"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"कम्यूनिटी"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"प्राइवेट स्पेस"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील जानकारी वाली सूचना का कॉन्टेंट छिपा है"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेयर करने के दौरान सुरक्षा के लिए, ऐप्लिकेशन का कॉन्टेंट छिपाया गया"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e69a59d..f6f7e8b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privatni prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Zajedničko"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privatni prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Skriven je osjetljiv sadržaj obavijesti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Sadržaj aplikacije sakriven je od dijeljenja zaslona radi sigurnosti"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f1ff236..5162616 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privát terület"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klón"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Közös"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privát terület"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Bizalmas értesítéstartalom elrejtve"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"A biztonság érdekében a képernyőmegosztástól elrejtett alkalmazástartalom"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 40812068..f2b6932 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Մասնավոր տարածք"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Կլոն"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Ընդհանուր"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Մասնավոր տարածք"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Ծանուցման զգայուն բովանդակությունը թաքցված է"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Անվտանգության նկատառումներից ելնելով՝ հավելվածի բովանդակությունը թաքցվել է էկրանի ցուցադրումից"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 866e946..d1a20f34 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang privasi"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Ruang privasi"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Konten notifikasi sensitif disembunyikan"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Konten aplikasi disembunyikan dari berbagi layar untuk alasan keamanan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 76ba64b..c8da948 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Leynirými"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Afrit"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Sameiginlegt"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Leynirými"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Viðkvæmt tilkynningaefni falið"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Efni forrits falið í skjádeilingu af öryggisástæðum"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 5e87dce..403c522 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spazio privato"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Condiviso"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Spazio privato"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Contenuti sensibili della notifica nascosti"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Contenuti dell\'app nascosti dalla condivisione schermo per sicurezza"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 439565d..21e9293 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -2039,7 +2039,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"הצמדה של <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"ביטול הצמדה"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"ביטול ההצמדה של <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"פרטי אפליקציה"</string>
+ <string name="app_info" msgid="6113278084877079851">"פרטי האפליקציה"</string>
<string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"תהליך ההדגמה מתחיל…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"מתבצע איפוס של המכשיר…"</string>
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"המרחב הפרטי"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"שכפול"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"שיתופי"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"המרחב הפרטי"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"יש תוכן רגיש בהתראה שהוסתר"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"תוכן האפליקציה מוסתר משיתוף המסך מטעמי אבטחה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index fcaef68..149f3cd 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"プライベート スペース"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"プライベート スペース"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"プライベートな通知内容は表示されません"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"セキュリティ上、画面共有ではアプリの内容は非表示となります"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 2b98c58..ee1e89d 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"კერძო სივრცე"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"კლონის შექმნა"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"საერთო"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"კერძო სივრცე"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"სენსიტიური შეტყობინების კონტენტი დამალულია"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ეკრანის გაზიარებიდან აპის კონტენტი დამალულია უსაფრთხოების მიზნით"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6e9eb12..63457e0 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Құпия кеңістік"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Жалпы"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Құпия кеңістік"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Хабарландырудың құпия контенті жасырылған."</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Қауіпсіздік мақсатында қолданба контенті экранды көрсету кезінде жасырылды."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 70f59c1..7294d4b 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"លំហឯកជន"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ក្លូន"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ទូទៅ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"លំហឯកជន"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"បានលាក់ខ្លឹមសារជូនដំណឹងដែលមានលក្ខណៈរសើប"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"បានលាក់ខ្លឹមសារកម្មវិធីពីការបង្ហាញអេក្រង់ដើម្បីសុវត្ថិភាព"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index f22c43a..3d7c782 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ಕ್ಲೋನ್"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ಸಮುದಾಯ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ಪ್ರೈವೆಟ್ ಸ್ಪೇಸ್"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ಸೂಕ್ಷ್ಮ ನೋಟಿಫಿಕೇಶನ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ಭದ್ರತೆಗಾಗಿ ಸ್ಕ್ರೀನ್ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯಲ್ಲಿ ಆ್ಯಪ್ ಕಂಟೆಂಟ್ ಅನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 99b8715..d815fe8 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"비공개 스페이스"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"클론"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"공동"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"비공개 스페이스"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"민감한 알림 콘텐츠 숨김"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"보안을 위해 화면 공유에서 앱 콘텐츠가 숨겨집니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 427010b..3cdf3ca 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Жеке мейкиндик"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Жалпы"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Жеке мейкиндик"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Купуя билдирменин мазмуну жашырылган"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Коопсуздук үчүн колдонмодогу контент бөлүшүлгөн экрандан жашырылды"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 4682bb0..80e09a6 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ພື້ນທີ່ສ່ວນບຸກຄົນ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ໂຄລນ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ສ່ວນກາງ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ພື້ນທີ່ສ່ວນບຸກຄົນ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ເນື້ອຫາການແຈ້ງເຕືອນທີ່ລະອຽດອ່ອນເຊື່ອງຢູ່"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ເນື້ອຫາແອັບຖືກເຊື່ອງໄວ້ຈາກການແບ່ງປັນໜ້າຈໍເພື່ອຄວາມປອດໄພ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6fbb9b8..b237241 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privati erdvė"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klonuoti"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Bendruomenės"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privati erdvė"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Neskelbtinos informacijos pranešimo turinys paslėptas"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Programos turinys paslėptas bendrinant ekraną saugumo sumetimais"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0bea4ff..cc902cd 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privātā telpa"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klons"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Kopīgs"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privātā telpa"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitīvs paziņojuma saturs ir paslēpts"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Drošības nolūkos lietotnes saturs kopīgotajā ekrānā ir paslēpts"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index d7a6dd2..b61b817 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватен простор"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клониран профил"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Профил на заедницата"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Приватен простор"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Содржината на чувствителните известувања е скриена"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Од безбедносни причини, содржините на апликацијата се скриени од споделувањето екран"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 4023336..9906470 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"സ്വകാര്യ സ്പേസ്"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ക്ലോൺ ചെയ്യുക"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"കമ്മ്യൂണൽ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"സ്വകാര്യ സ്പേസ്"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"സൂക്ഷ്മമായി കൈകാര്യം ചെയ്യേണ്ട അറിയിപ്പ് ഉള്ളടക്കം മറച്ചിരിക്കുന്നു"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ആപ്പ് ഉള്ളടക്കം, അതിന്റെ സുരക്ഷയ്ക്കായി സ്ക്രീൻ പങ്കിടലിൽ നിന്ന് മറച്ചിരിക്കുന്നു"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9aa18e2..22f8f15 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Хаалттай орон зай"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клон"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Нийтийн"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Хаалттай орон зай"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Эмзэг мэдэгдлийн контентыг нуусан"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Аюулгүй байдлын улмаас аппын контентыг дэлгэц хуваалцахаас нуусан"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a115e2c..36d0bba 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"खाजगी स्पेस"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"सामुदायिक"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"खाजगी स्पेस"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील नोटिफिकेशनचा आशय लपवलेला आहे"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रीन शेअर करताना सुरक्षेसाठी अॅपमधील आशय लपवला आहे"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 2fa571c..c215f62 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Ruang persendirian"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umum"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Ruang privasi"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Kandungan pemberitahuan yang sensitif disembunyikan"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Kandungan apl disembunyikan daripada perkongsian skrin untuk keselamatan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 364a7b1..f030ef2 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"သီးသန့်နေရာ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ပုံတူပွားရန်"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"အများသုံး"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"သီးသန့်နေရာ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"သတိထားရမည့် အကြောင်းကြားချက်ပါ အချက်အလက်ကို ဖျောက်ထားသည်"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"အက်ပ်အကြောင်းအရာသည် လုံခြုံရေးအတွက် မျက်နှာပြင် မျှဝေခြင်းမှ ဖျောက်ထားသည်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e2de428..116c586 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Felles"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privat område"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Sensitivt varselinnhold er skjult"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av sikkerhetsgrunner er appinnholdet skjult for skjermdelingen"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 8d5f560..a202d4c 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"निजी स्पेस"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"क्लोन"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"सामुदायिक"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"निजी स्पेस"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"संवेदनशील सूचनासम्बन्धी सामग्री लुकाइएको छ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"स्क्रिन सेयर गर्दा सुरक्षाका लागि एपमा भएको सामग्री लुकाइएको छ"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5bc6c44..51d8959 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privégedeelte"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Kloon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Gemeenschappelijk"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privégedeelte"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Content van gevoelige meldingen verborgen"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"App-content verborgen voor scherm delen vanwege beveiligingsrisico\'s"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 4c7868d..90ab620 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"କ୍ଲୋନ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"କମ୍ୟୁନାଲ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ସମ୍ୱେଦନଶୀଳ ବିଜ୍ଞପ୍ତି ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ସୁରକ୍ଷା ପାଇଁ ସ୍କ୍ରିନ ସେୟାରରୁ ଆପ ବିଷୟବସ୍ତୁକୁ ଲୁଚାଯାଇଛି"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 38780b6..de91ea7 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ਕਲੋਨ"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ਭਾਈਚਾਰਕ"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"ਲੁਕੀ ਹੋਈ ਸੰਵੇਦਨਸ਼ੀਲ ਸੂਚਨਾ ਸਮੱਗਰੀ"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ਐਪ ਸਮੱਗਰੀ ਨੂੰ ਸੁਰੱਖਿਆ ਲਈ ਸਕ੍ਰੀਨ ਸਾਂਝਾਕਰਨ ਤੋਂ ਲੁਕਾਇਆ ਗਿਆ ਹੈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 95e1a30..d9a95b8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Przestrzeń prywatna"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wspólny"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Przestrzeń prywatna"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Treść poufnego powiadomienia została ukryta"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ze względów bezpieczeństwa zawartość aplikacji jest niewidoczna podczas udostępniania ekranu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index c9d36b1..cd3a7c5 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espaço privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f1b2bd0..d8fe4fe 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -733,7 +733,7 @@
<skip />
<string name="face_acquired_recalibrate_alt" msgid="5702674220280332115">"Não é possível criar o seu modelo de rosto. Tente novamente."</string>
<string name="face_acquired_dark_glasses_detected_alt" msgid="4052123776406041972">"Óculos escuros detetados. O seu rosto tem de estar completamente visível."</string>
- <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Máscara detetada. Todo o rosto tem de estar visível"</string>
+ <string name="face_acquired_mouth_covering_detected_alt" msgid="1122294982850589766">"Cobertura facial detetada. O seu rosto tem de estar completamente visível."</string>
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Não pode validar o rosto. Hardware não disponível."</string>
@@ -1292,7 +1292,7 @@
<string name="android_upgrading_complete" msgid="409800058018374746">"A concluir o arranque."</string>
<string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Premiu o botão ligar/desligar. Geralmente, esta ação desliga o ecrã.\n\nExperimente tocar levemente ao configurar a sua impressão digital."</string>
<string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Para terminar, desligue o ecrã"</string>
- <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Desligar"</string>
+ <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Desativar"</string>
<string name="fp_power_button_bp_title" msgid="5585506104526820067">"Continuar a validar a impressão digital?"</string>
<string name="fp_power_button_bp_message" msgid="2983163038168903393">"Premiu o botão ligar/desligar. Geralmente, esta ação desliga o ecrã.\n\nExperimente tocar levemente para validar a sua impressão digital."</string>
<string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Desligar ecrã"</string>
@@ -1438,7 +1438,7 @@
<string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"A app <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras aplicações"</string>
<string name="alert_windows_notification_title" msgid="6331662751095228536">"O <xliff:g id="NAME">%s</xliff:g> sobrepõe-se a outras app"</string>
<string name="alert_windows_notification_message" msgid="6538171456970725333">"Se não quer que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
- <string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desligar"</string>
+ <string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Desativar"</string>
<string name="ext_media_checking_notification_title" msgid="8299199995416510094">"A verificar o <xliff:g id="NAME">%s</xliff:g>…"</string>
<string name="ext_media_checking_notification_message" msgid="2231566971425375542">"A rever o conteúdo atual…"</string>
<string name="ext_media_checking_notification_message" product="tv" msgid="7986154434946021415">"A analisar o armazenamento de multimédia"</string>
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comum"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espaço privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo das notificações sensíveis ocultado"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo da app ocultado da partilha de ecrã por motivos de segurança"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c9d36b1..cd3a7c5 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Espaço privado"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Público"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Espaço privado"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conteúdo de notificação sensível oculto"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conteúdo do app oculto no compartilhamento de tela por motivos de segurança"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e14aec7..d43556d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Spațiu privat"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clonă"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Comun"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Spațiu privat"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Conținutul sensibil din notificări a fost ascuns"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Conținutul aplicației este ascuns de permiterea accesului la ecran din motive de securitate"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 79b0daa..16ddae8 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Частное пространство"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонированный"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Совместный"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Частное пространство"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Конфиденциальная информация в уведомлении скрыта"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Содержимое приложения исключено из демонстрации экрана в целях безопасности."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 1e69e0b..4f6e756 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"රහසිගත අවකාශය"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"ක්ලෝන කරන්න"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"වාර්ගික"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"රහසිගත අවකාශය"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"සංවේදී දැනුම්දීම් අන්තර්ගතය සැඟවී ඇත"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ආරක්ෂාව සඳහා යෙදුම් අන්තර්ගතය තිරය බෙදා ගැනීමෙන් සඟවා ඇත"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c7ca9f4..aeea7b6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2040,7 +2040,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"Pripnúť <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Uvoľniť"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Odopnúť <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"Info o aplikácii"</string>
+ <string name="app_info" msgid="6113278084877079851">"Informácie o aplikácii"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Spúšťa sa ukážka…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Resetuje sa zariadenie…"</string>
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Súkromný priestor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Spoločný"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Súkromný priestor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Obsah citlivého upozornenia je skrytý"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Obsah aplikácie bol na účely zabezpečenia skrytý v zdieľaní obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 4f23a54..d3ce57c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Zasebni prostor"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Skupno"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Zasebni prostor"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Občutljiva vsebina obvestila je bila skrita"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Pri deljenju zaslona je vsebina aplikacije skrita zaradi varnosti"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index c49402b..de02100 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Hapësira private"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"I përbashkët"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Hapësira private"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Përmbajtjet delikate të njoftimeve janë fshehur"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Përmbajtja e aplikacionit është fshehur nga ndarja e ekranit për arsye sigurie"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2b3f75a..f200ac1 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2408,8 +2408,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватан простор"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Клонирано"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Заједничко"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Приватан простор"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Осетљив садржај обавештења је скривен"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Садржај апликације је скривен за дељење садржаја екрана због безбедности"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 2833381..589414d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -2038,7 +2038,7 @@
<string name="pin_specific_target" msgid="7824671240625957415">"Fäst <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="unpin_target" msgid="3963318576590204447">"Lossa"</string>
<string name="unpin_specific_target" msgid="3859828252160908146">"Lossa <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="app_info" msgid="6113278084877079851">"Info om appen"</string>
+ <string name="app_info" msgid="6113278084877079851">"Appinformation"</string>
<string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="6577581216125805905">"Demo startas …"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Enheten återställs …"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Privat område"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klona"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Allmän"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Privat område"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Känsligt aviseringsinnehåll dolt"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Av säkerhetsskäl döljs appinnehållet vid skärmdelning"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d3af99f..4b50cb7 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Sehemu ya faragha"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nakala"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Wasifu wa pamoja"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Sehemu ya faragha"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Maudhui nyeti kwenye arifa yamefichwa"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Maudhui ya programu yamefichwa ili yasionekane kwenye skrini ya pamoja kwa sababu za kiusalama"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 37abcef..6ad8f59 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ரகசிய இடம்"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"குளோன்"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"பொது"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ரகசிய இடம்"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"உணர்வுபூர்வமான அறிவிப்பு உள்ளடக்கம் மறைக்கப்பட்டது"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"பாதுகாப்பிற்காக, திரைப் பகிர்வில் இருந்து ஆப்ஸ் உள்ளடக்கம் மறைக்கப்பட்டுள்ளது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 2766248..91f9ef2 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"ప్రైవేట్ స్పేస్"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"క్లోన్"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"కమ్యూనల్"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"ప్రైవేట్ స్పేస్"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"గోప్యమైన నోటిఫికేషన్ కంటెంట్ దాచబడింది"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"సెక్యూరిటీ కోసం స్క్రీన్ షేర్ నుండి యాప్ కంటెంట్ దాచబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1f2a091..eb102fc 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"พื้นที่ส่วนตัว"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"โคลน"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"ส่วนกลาง"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"พื้นที่ส่วนตัว"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"เนื้อหาการแจ้งเตือนที่ละเอียดอ่อนซ่อนอยู่"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"ซ่อนเนื้อหาแอปจากการแชร์หน้าจอเพื่อความปลอดภัย"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 7bce4b7..de499d34 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Pribadong space"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Communal"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Pribadong space"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Nakatago ang content ng sensitibong notification"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nakatago ang content ng app mula sa pagbabahagi ng screen para sa seguridad"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index cbfb770..7dab236 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Özel alan"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Klon"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Paylaşılan"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Özel alan"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Hassas bildirim içerikleri gizlendi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Uygulama içerikleri, güvenlik nedeniyle ekran paylaşımında gizlendi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5266acd..22c7272 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2409,8 +2409,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Приватний простір"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Копія профілю"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Спільний профіль"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Приватний простір"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Чутливий вміст сповіщення приховано"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"З міркувань безпеки вміст додатка приховано під час показу екрана"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2fe52f8..0d878c9 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"پرائیویٹ اسپیس"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"کلون"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"کمیونل"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"پرائیویٹ اسپیس"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"حساس اطلاعی مواد چھپا ہوا ہے"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"سیکیورٹی کے مد نظر ایپ کا مواد اسکرین کے اشتراک سے چھپا ہوا ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d40f383..fc5d8ee 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Maxfiy makon"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nusxalash"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Umumiy"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Maxfiy makon"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Bildirishnomadagi maxfiy axborot berkitildi"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Ekran namoyishida xavfsizlik maqsadida ilova kontenti berkitildi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1051cda..4619be3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Không gian riêng tư"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Nhân bản"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Dùng chung"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Không gian riêng tư"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Đã ẩn nội dung thông báo nhạy cảm"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Nội dung ứng dụng bị ẩn khỏi tính năng chia sẻ màn hình vì lý do bảo mật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d16a353..a6c62dc 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -581,7 +581,7 @@
<string name="permlab_changeTetherState" msgid="9079611809931863861">"更改网络共享连接"</string>
<string name="permdesc_changeTetherState" msgid="3025129606422533085">"允许应用更改绑定网络连接的状态。"</string>
<string name="permlab_accessWifiState" msgid="5552488500317911052">"查看WLAN连接"</string>
- <string name="permdesc_accessWifiState" msgid="6913641669259483363">"允许该应用查看WLAN网络的相关信息,例如是否启用了WLAN以及连接的WLAN设备的名称。"</string>
+ <string name="permdesc_accessWifiState" msgid="6913641669259483363">"允许该应用查看 WLAN 网络的相关信息,例如是否启用了 WLAN 以及连接的 WLAN 设备的名称。"</string>
<string name="permlab_changeWifiState" msgid="7947824109713181554">"连接WLAN网络和断开连接"</string>
<string name="permdesc_changeWifiState" msgid="7170350070554505384">"允许该应用与WLAN接入点建立和断开连接,以及更改WLAN网络的设备配置。"</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"允许接收WLAN多播"</string>
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"私密空间"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"克隆"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"私密空间"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"已隐藏敏感通知内容"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"为安全起见而在屏幕共享画面中处于隐藏状态的应用内容"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 672a638..f9b10a2 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共用"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"私人空間"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"已隱藏敏感通知內容"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,應用程式內容已從分享螢幕畫面隱藏"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 8a224ed..4dce59a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"私人空間"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"複製"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"共通"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"私人空間"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"系統已隱藏含有私密資訊的通知內容"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"為安全起見,分享螢幕畫面未顯示應用程式內容"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 27bd3c9..60cb31b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2407,8 +2407,7 @@
<string name="accessibility_label_private_profile" msgid="1436459319135548969">"Indawo engasese"</string>
<string name="accessibility_label_clone_profile" msgid="7579118375042398784">"Yenza i-Clone"</string>
<string name="accessibility_label_communal_profile" msgid="1437173163111334791">"Okomphakathi"</string>
- <!-- no translation found for private_space_biometric_prompt_title (5777592909271728154) -->
- <skip />
+ <string name="private_space_biometric_prompt_title" msgid="5777592909271728154">"Indawo engasese"</string>
<string name="redacted_notification_message" msgid="1520587845842228816">"Okuqukethwe kwesaziso esizwelayo kufihliwe"</string>
<string name="redacted_notification_action_title" msgid="6942924973335920935"></string>
<string name="screen_not_shared_sensitive_content" msgid="7058419185079565001">"Okuqukethwe kwe-app kufihliwe kusuka ekwabelaneni kwesikrini ngokuvikelwa"</string>
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
index 5f78b2a..42501c1 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java
@@ -27,6 +27,7 @@
import android.hardware.broadcastradio.DabTableEntry;
import android.hardware.broadcastradio.IdentifierType;
import android.hardware.broadcastradio.Metadata;
+import android.hardware.broadcastradio.ProgramFilter;
import android.hardware.broadcastradio.ProgramIdentifier;
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.Properties;
@@ -41,6 +42,7 @@
import android.hardware.radio.UniqueProgramIdentifier;
import android.os.ServiceSpecificException;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.util.ArraySet;
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
@@ -93,6 +95,11 @@
private static final long TEST_HD_LOCATION_VALUE = 0x4E647007665CF6L;
private static final long TEST_VENDOR_ID_VALUE = 9_901;
+ private static final ProgramSelector.Identifier TEST_INVALID_ID =
+ new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_INVALID, 1);
+ private static final ProgramIdentifier TEST_HAL_INVALID_ID =
+ AidlTestUtils.makeHalIdentifier(IdentifierType.INVALID, 1);
+
private static final ProgramSelector.Identifier TEST_DAB_SID_EXT_ID =
new ProgramSelector.Identifier(
ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE);
@@ -139,7 +146,7 @@
private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING;
private static final RadioManager.ModuleProperties MODULE_PROPERTIES =
- convertToModuleProperties();
+ createModuleProperties();
private static final Announcement ANNOUNCEMENT =
ConversionUtils.announcementFromHalAnnouncement(
AidlTestUtils.makeAnnouncement(TEST_ENABLED_TYPE, TEST_ANNOUNCEMENT_FREQUENCY));
@@ -291,6 +298,37 @@
}
@Test
+ public void propertiesFromHalProperties_withoutAmFmAndDabConfigs() {
+ RadioManager.ModuleProperties properties = createModuleProperties(/* amFmConfig= */ null,
+ new DabTableEntry[]{});
+
+ expect.withMessage("Empty AM/FM config")
+ .that(properties.getBands()).asList().isEmpty();
+ expect.withMessage("Empty DAB config")
+ .that(properties.getDabFrequencyTable()).isNull();
+ }
+
+ @Test
+ public void propertiesFromHalProperties_withInvalidBand() {
+ AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig();
+ amFmRegionConfig.ranges = new AmFmBandRange[]{createAmFmBandRange(/* lowerBound= */ 50000,
+ /* upperBound= */ 60000, /* spacing= */ 10),
+ createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING)};
+
+ RadioManager.ModuleProperties properties = createModuleProperties(amFmRegionConfig,
+ new DabTableEntry[]{});
+
+ RadioManager.BandDescriptor[] bands = properties.getBands();
+ expect.withMessage("Band descriptors").that(bands).hasLength(1);
+ expect.withMessage("FM band frequency lower limit")
+ .that(bands[0].getLowerLimit()).isEqualTo(FM_LOWER_LIMIT);
+ expect.withMessage("FM band frequency upper limit")
+ .that(bands[0].getUpperLimit()).isEqualTo(FM_UPPER_LIMIT);
+ expect.withMessage("FM band frequency spacing")
+ .that(bands[0].getSpacing()).isEqualTo(FM_SPACING);
+ }
+
+ @Test
public void identifierToHalProgramIdentifier_withDabId() {
ProgramIdentifier halDabId =
ConversionUtils.identifierToHalProgramIdentifier(TEST_DAB_SID_EXT_ID);
@@ -358,6 +396,13 @@
}
@Test
+ public void identifierFromHalProgramIdentifier_withInvalidIdentifier() {
+ expect.withMessage("Identifier converted from invalid HAL identifier")
+ .that(ConversionUtils.identifierFromHalProgramIdentifier(TEST_HAL_INVALID_ID))
+ .isNull();
+ }
+
+ @Test
public void programSelectorToHalProgramSelector_withValidSelector() {
android.hardware.broadcastradio.ProgramSelector halDabSelector =
ConversionUtils.programSelectorToHalProgramSelector(TEST_DAB_SELECTOR);
@@ -370,6 +415,23 @@
}
@Test
+ public void programSelectorToHalProgramSelector_withInvalidSecondaryId() {
+ ProgramSelector dabSelector = new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB,
+ TEST_DAB_SID_EXT_ID, new ProgramSelector.Identifier[]{TEST_INVALID_ID,
+ TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID}, /* vendorIds= */ null);
+
+ android.hardware.broadcastradio.ProgramSelector halDabSelector =
+ ConversionUtils.programSelectorToHalProgramSelector(dabSelector);
+
+ expect.withMessage("Primary identifier of converted HAL DAB selector with invalid "
+ + "secondary id").that(halDabSelector.primaryId)
+ .isEqualTo(TEST_HAL_DAB_SID_EXT_ID);
+ expect.withMessage("Secondary identifiers of converted HAL DAB selector with "
+ + "invalid secondary id").that(halDabSelector.secondaryIds).asList()
+ .containsExactly(TEST_HAL_DAB_FREQUENCY_ID, TEST_HAL_DAB_ENSEMBLE_ID);
+ }
+
+ @Test
public void programSelectorFromHalProgramSelector_withValidSelector() {
android.hardware.broadcastradio.ProgramSelector halDabSelector =
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
@@ -386,6 +448,33 @@
}
@Test
+ public void programSelectorFromHalProgramSelector_withInvalidSelector() {
+ android.hardware.broadcastradio.ProgramSelector invalidSelector =
+ AidlTestUtils.makeHalSelector(TEST_HAL_INVALID_ID, new ProgramIdentifier[]{});
+
+ expect.withMessage("Selector converted from invalid HAL selector")
+ .that(ConversionUtils.programSelectorFromHalProgramSelector(invalidSelector))
+ .isNull();
+ }
+
+ @Test
+ public void programSelectorFromHalProgramSelector_withInvalidSecondaryId() {
+ android.hardware.broadcastradio.ProgramSelector halDabSelector =
+ AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
+ TEST_HAL_INVALID_ID, TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
+
+ ProgramSelector dabSelector =
+ ConversionUtils.programSelectorFromHalProgramSelector(halDabSelector);
+
+ expect.withMessage("Primary identifier of converted DAB selector with invalid "
+ + "secondary id").that(dabSelector.getPrimaryId())
+ .isEqualTo(TEST_DAB_SID_EXT_ID);
+ expect.withMessage("Secondary identifiers of converted DAB selector with invalid "
+ + "secondary id").that(dabSelector.getSecondaryIds()).asList()
+ .containsExactly(TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID);
+ }
+
+ @Test
public void programInfoFromHalProgramInfo_withValidProgramInfo() {
android.hardware.broadcastradio.ProgramSelector halDabSelector =
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
@@ -628,11 +717,41 @@
.that(Utils.getBand(/* freq= */ 110000)).isEqualTo(Utils.FrequencyBand.UNKNOWN);
}
- private static RadioManager.ModuleProperties convertToModuleProperties() {
+ @Test
+ public void filterToHalProgramFilter_withNullFilter() {
+ ProgramFilter filter = ConversionUtils.filterToHalProgramFilter(null);
+
+ expect.withMessage("Filter identifier types").that(filter.identifierTypes)
+ .asList().isEmpty();
+ expect.withMessage("Filter identifiers").that(filter.identifiers).asList()
+ .isEmpty();
+ }
+
+ @Test
+ public void filterToHalProgramFilter_withInvalidIdentifier() {
+ Set<ProgramSelector.Identifier> identifiers =
+ new ArraySet<ProgramSelector.Identifier>(2);
+ identifiers.add(TEST_INVALID_ID);
+ identifiers.add(TEST_DAB_SID_EXT_ID);
+ ProgramList.Filter filter = new ProgramList.Filter(/* identifierTypes */ new ArraySet<>(),
+ identifiers, /* includeCategories= */ true, /* excludeModifications= */ false);
+ ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(filter);
+
+ expect.withMessage("Filter identifiers with invalid ones removed")
+ .that(halFilter.identifiers).asList().containsExactly(
+ ConversionUtils.identifierToHalProgramIdentifier(TEST_DAB_SID_EXT_ID));
+ }
+
+ private static RadioManager.ModuleProperties createModuleProperties() {
AmFmRegionConfig amFmConfig = createAmFmRegionConfig();
DabTableEntry[] dabTableEntries = new DabTableEntry[]{
createDabTableEntry(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1),
createDabTableEntry(DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2)};
+ return createModuleProperties(amFmConfig, dabTableEntries);
+ }
+
+ private static RadioManager.ModuleProperties createModuleProperties(
+ AmFmRegionConfig amFmConfig, DabTableEntry[] dabTableEntries) {
Properties properties = createHalProperties();
return ConversionUtils.propertiesFromHalProperties(TEST_ID, TEST_SERVICE_NAME, properties,
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
index 10ac05d..a952bde 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
@@ -16,13 +16,12 @@
package com.android.server.broadcastradio.aidl;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,9 +31,13 @@
import android.hardware.radio.IAnnouncementListener;
import android.hardware.radio.ICloseHandle;
import android.hardware.radio.RadioManager;
+import android.os.ParcelableException;
import android.os.RemoteException;
+import com.google.common.truth.Expect;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -50,6 +53,9 @@
private static final RadioManager.ModuleProperties TEST_MODULE_PROPERTIES =
AidlTestUtils.makeDefaultModuleProperties();
+ @Rule
+ public final Expect mExpect = Expect.create();
+
// Mocks
@Mock
private IBroadcastRadio mBroadcastRadioMock;
@@ -77,13 +83,13 @@
@Test
public void getService() {
- assertWithMessage("Service of radio module")
+ mExpect.withMessage("Service of radio module")
.that(mRadioModule.getService()).isEqualTo(mBroadcastRadioMock);
}
@Test
public void getProperties() {
- assertWithMessage("Module properties of radio module")
+ mExpect.withMessage("Module properties of radio module")
.that(mRadioModule.getProperties()).isEqualTo(TEST_MODULE_PROPERTIES);
}
@@ -93,7 +99,7 @@
Bitmap imageTest = mRadioModule.getImage(imageId);
- assertWithMessage("Image from radio module").that(imageTest).isNull();
+ mExpect.withMessage("Image from radio module").that(imageTest).isNull();
}
@Test
@@ -104,7 +110,7 @@
mRadioModule.getImage(invalidImageId);
});
- assertWithMessage("Exception for getting image with invalid ID")
+ mExpect.withMessage("Exception for getting image with invalid ID")
.that(thrown).hasMessageThat().contains("Image ID is missing");
}
@@ -117,6 +123,18 @@
}
@Test
+ public void addAnnouncementListener_whenHalThrowsRemoteException() throws Exception {
+ doThrow(new RuntimeException("HAL service died")).when(mBroadcastRadioMock)
+ .registerAnnouncementListener(any(), any());
+
+ ParcelableException thrown = assertThrows(ParcelableException.class, () ->
+ mRadioModule.addAnnouncementListener(mListenerMock, new int[]{TEST_ENABLED_TYPE}));
+
+ mExpect.withMessage("Exception for adding announcement listener when HAL service died")
+ .that(thrown).hasMessageThat().contains("unknown error");
+ }
+
+ @Test
public void onListUpdate_forAnnouncementListener() throws Exception {
android.hardware.broadcastradio.Announcement halAnnouncement =
AidlTestUtils.makeAnnouncement(TEST_ENABLED_TYPE, /* selectorFreq= */ 96300);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index 755bcdb..4ded91d 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -421,6 +421,19 @@
}
@Test
+ public void tune_withClosedTuner_fails() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ mTunerSessions[0].close();
+
+ IllegalStateException thrown = assertThrows(IllegalStateException.class,
+ () -> mTunerSessions[0].tune(sel));
+
+ expect.withMessage("Exception for tuning on closed tuner").that(thrown).hasMessageThat()
+ .contains("Tuner is closed");
+ }
+
+ @Test
public void step_withDirectionUp() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[1];
ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq);
@@ -1149,6 +1162,20 @@
}
@Test
+ public void onCurrentProgramInfoChanged_withLowerSdkVersion_doesNotInvokesCallback()
+ throws Exception {
+ doReturn(false).when(() -> CompatChanges.isChangeEnabled(
+ eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
+ openAidlClients(/* numClients= */ 1);
+
+ mHalTunerCallback.onCurrentProgramInfoChanged(
+ AidlTestUtils.programInfoToHalProgramInfo(TEST_DAB_INFO));
+
+ verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).never())
+ .onCurrentProgramInfoChanged(any());
+ }
+
+ @Test
public void onTuneFailed_forTunerCallback() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
@@ -1165,6 +1192,20 @@
}
@Test
+ public void onTuneFailed_withLowerSdkVersion_doesNotInvokesCallback()
+ throws Exception {
+ doReturn(false).when(() -> CompatChanges.isChangeEnabled(
+ eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
+ openAidlClients(/* numClients= */ 1);
+
+ mHalTunerCallback.onTuneFailed(Result.CANCELED,
+ ConversionUtils.programSelectorToHalProgramSelector(TEST_DAB_SELECTOR));
+
+ verify(mAidlTunerCallbackMocks[0], after(CALLBACK_TIMEOUT_MS).never())
+ .onTuneFailed(anyInt(), any());
+ }
+
+ @Test
public void onAntennaStateChange_forTunerCallback() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
@@ -1231,6 +1272,36 @@
}
}
+ @Test
+ public void openSession_withNonNullAntennaState() throws Exception {
+ boolean antennaConnected = false;
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+ openAidlClients(/* numClients= */ 1);
+ mHalTunerCallback.onAntennaStateChange(antennaConnected);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+ }
+
+ @Test
+ public void openSession_withNonNullCurrentProgramInfo() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ RadioManager.ProgramInfo tuneInfo = AidlTestUtils.makeProgramInfo(initialSel,
+ SIGNAL_QUALITY);
+ mTunerSessions[0].tune(initialSel);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ }
+
private void openAidlClients(int numClients) throws Exception {
mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
mTunerSessions = new TunerSession[numClients];
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
index 123e02c..4cb012c 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ConvertTest.java
@@ -21,7 +21,6 @@
import android.hardware.broadcastradio.V2_0.DabTableEntry;
import android.hardware.broadcastradio.V2_0.IdentifierType;
import android.hardware.broadcastradio.V2_0.Properties;
-import android.hardware.broadcastradio.V2_0.VendorKeyValue;
import android.hardware.radio.Announcement;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
@@ -149,6 +148,26 @@
}
@Test
+ public void propertiesFromHalProperties_withInvalidBand() {
+ AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig();
+ amFmRegionConfig.ranges = new ArrayList<>(Arrays.asList(createAmFmBandRange(
+ /* lowerBound= */ 50000, /* upperBound= */ 60000, /* spacing= */ 10),
+ createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING)));
+
+ RadioManager.ModuleProperties properties = convertToModuleProperties(amFmRegionConfig,
+ new ArrayList<>());
+
+ RadioManager.BandDescriptor[] bands = properties.getBands();
+ expect.withMessage("Band descriptors").that(bands).hasLength(1);
+ expect.withMessage("FM band frequency lower limit")
+ .that(bands[0].getLowerLimit()).isEqualTo(FM_LOWER_LIMIT);
+ expect.withMessage("FM band frequency upper limit")
+ .that(bands[0].getUpperLimit()).isEqualTo(FM_UPPER_LIMIT);
+ expect.withMessage("FM band frequency spacing")
+ .that(bands[0].getSpacing()).isEqualTo(FM_SPACING);
+ }
+
+ @Test
public void announcementFromHalAnnouncement_typesMatch() {
expect.withMessage("Announcement type")
.that(ANNOUNCEMENT.getType()).isEqualTo(TEST_ENABLED_TYPE);
@@ -184,15 +203,20 @@
List<DabTableEntry> dabTableEntries = Arrays.asList(
createDabTableEntry(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1),
createDabTableEntry(DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2));
- Properties properties = createHalProperties();
+ return convertToModuleProperties(amFmConfig, dabTableEntries);
+ }
+
+ private static RadioManager.ModuleProperties convertToModuleProperties(
+ AmFmRegionConfig amFmConfig, List<DabTableEntry> dabTableEntries) {
+ Properties properties = createHalProperties();
return Convert.propertiesFromHal(TEST_ID, TEST_SERVICE_NAME, properties,
amFmConfig, dabTableEntries);
}
private static AmFmRegionConfig createAmFmRegionConfig() {
AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig();
- amFmRegionConfig.ranges = new ArrayList<AmFmBandRange>(Arrays.asList(
+ amFmRegionConfig.ranges = new ArrayList<>(Arrays.asList(
createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING),
createAmFmBandRange(AM_LOWER_LIMIT, AM_UPPER_LIMIT, AM_SPACING)));
return amFmRegionConfig;
@@ -222,7 +246,7 @@
halProperties.product = TEST_PRODUCT;
halProperties.version = TEST_VERSION;
halProperties.serial = TEST_SERIAL;
- halProperties.vendorInfo = new ArrayList<VendorKeyValue>(Arrays.asList(
+ halProperties.vendorInfo = new ArrayList<>(Arrays.asList(
TestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_1, VENDOR_INFO_VALUE_1),
TestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_2, VENDOR_INFO_VALUE_2)));
return halProperties;
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
index 6edfa02..898ef57 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
@@ -29,8 +29,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.timeout;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.google.common.truth.Truth.assertWithMessage;
-
import static org.junit.Assert.assertThrows;
import android.graphics.Bitmap;
@@ -57,8 +55,11 @@
import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase;
import com.android.server.broadcastradio.RadioServiceUserController;
+import com.google.common.truth.Expect;
+
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;
@@ -98,6 +99,9 @@
private ProgramInfo mHalCurrentInfo;
private TunerSession[] mTunerSessions;
+ @Rule
+ public final Expect mExpect = Expect.create();
+
@Mock
private UserHandle mUserHandleMock;
@Mock
@@ -206,7 +210,7 @@
openAidlClients(numSessions);
for (int index = 0; index < numSessions; index++) {
- assertWithMessage("Session of index %s close state", index)
+ mExpect.withMessage("Session of index %s close state", index)
.that(mTunerSessions[index].isClosed()).isFalse();
}
}
@@ -238,7 +242,7 @@
RadioManager.BandConfig config = mTunerSessions[0].getConfiguration();
- assertWithMessage("Session configuration").that(config)
+ mExpect.withMessage("Session configuration").that(config)
.isEqualTo(FM_BAND_CONFIG);
}
@@ -248,7 +252,7 @@
mTunerSessions[0].setMuted(/* mute= */ false);
- assertWithMessage("Session mute state after setting unmuted")
+ mExpect.withMessage("Session mute state after setting unmuted")
.that(mTunerSessions[0].isMuted()).isFalse();
}
@@ -258,7 +262,7 @@
mTunerSessions[0].setMuted(/* mute= */ true);
- assertWithMessage("Session mute state after setting muted")
+ mExpect.withMessage("Session mute state after setting muted")
.that(mTunerSessions[0].isMuted()).isTrue();
}
@@ -268,7 +272,7 @@
mTunerSessions[0].close();
- assertWithMessage("Close state of broadcast radio service session")
+ mExpect.withMessage("Close state of broadcast radio service session")
.that(mTunerSessions[0].isClosed()).isTrue();
}
@@ -282,11 +286,11 @@
for (int index = 0; index < numSessions; index++) {
if (index == closeIdx) {
- assertWithMessage(
+ mExpect.withMessage(
"Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isTrue();
} else {
- assertWithMessage(
+ mExpect.withMessage(
"Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isFalse();
}
@@ -301,7 +305,21 @@
mTunerSessions[0].close(errorCode);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onError(errorCode);
- assertWithMessage("Close state of broadcast radio service session")
+ mExpect.withMessage("Close state of broadcast radio service session")
+ .that(mTunerSessions[0].isClosed()).isTrue();
+ }
+
+ @Test
+ public void close_forMultipleTimes() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ int errorCode = RadioTuner.ERROR_SERVER_DIED;
+ mTunerSessions[0].close(errorCode);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onError(errorCode);
+
+ mTunerSessions[0].close(errorCode);
+
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onError(errorCode);
+ mExpect.withMessage("State of closing broadcast radio service session twice")
.that(mTunerSessions[0].isClosed()).isTrue();
}
@@ -315,7 +333,7 @@
for (int index = 0; index < numSessions; index++) {
verify(mAidlTunerCallbackMocks[index], CALLBACK_TIMEOUT).onError(errorCode);
- assertWithMessage("Close state of broadcast radio service session of index %s", index)
+ mExpect.withMessage("Close state of broadcast radio service session of index %s", index)
.that(mTunerSessions[index].isClosed()).isTrue();
}
}
@@ -365,7 +383,7 @@
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
() -> mTunerSessions[0].tune(unsupportedSelector));
- assertWithMessage("Exception for tuning on unsupported program selector")
+ mExpect.withMessage("Exception for tuning on unsupported program selector")
.that(thrown).hasMessageThat().contains("tune: NOT_SUPPORTED");
}
@@ -393,11 +411,24 @@
mTunerSessions[0].tune(sel);
});
- assertWithMessage("Unknown error HAL exception when tuning")
+ mExpect.withMessage("Unknown error HAL exception when tuning")
.that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
}
@Test
+ public void tune_withClosedTuner_fails() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector sel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ mTunerSessions[0].close();
+
+ IllegalStateException thrown = assertThrows(IllegalStateException.class,
+ () -> mTunerSessions[0].tune(sel));
+
+ mExpect.withMessage("Exception for tuning on closed tuner").that(thrown).hasMessageThat()
+ .contains("Tuner is closed");
+ }
+
+ @Test
public void step_withDirectionUp() throws Exception {
long initFreq = AM_FM_FREQUENCY_LIST[1];
ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
@@ -454,7 +485,7 @@
mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Exception for stepping when HAL is in invalid state")
+ mExpect.withMessage("Exception for stepping when HAL is in invalid state")
.that(thrown).hasMessageThat().contains(Result.toString(Result.INVALID_STATE));
}
@@ -533,7 +564,7 @@
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
});
- assertWithMessage("Internal error HAL exception when seeking")
+ mExpect.withMessage("Internal error HAL exception when seeking")
.that(thrown).hasMessageThat().contains(Result.toString(Result.INTERNAL_ERROR));
}
@@ -566,7 +597,7 @@
mTunerSessions[0].cancel();
});
- assertWithMessage("Exception for canceling when HAL throws remote exception")
+ mExpect.withMessage("Exception for canceling when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -579,7 +610,7 @@
mTunerSessions[0].getImage(imageId);
});
- assertWithMessage("Get image exception")
+ mExpect.withMessage("Get image exception")
.that(thrown).hasMessageThat().contains("Image ID is missing");
}
@@ -590,7 +621,7 @@
Bitmap imageTest = mTunerSessions[0].getImage(imageId);
- assertWithMessage("Null image").that(imageTest).isEqualTo(null);
+ mExpect.withMessage("Null image").that(imageTest).isEqualTo(null);
}
@Test
@@ -603,7 +634,7 @@
mTunerSessions[0].getImage(/* id= */ 1);
});
- assertWithMessage("Exception for getting image when HAL throws remote exception")
+ mExpect.withMessage("Exception for getting image when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -649,7 +680,7 @@
mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
});
- assertWithMessage("Unknown error HAL exception when updating program list")
+ mExpect.withMessage("Unknown error HAL exception when updating program list")
.that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
}
@@ -686,7 +717,7 @@
boolean isSupported = mTunerSessions[0].isConfigFlagSupported(flag);
verify(mHalTunerSessionMock).isConfigFlagSet(eq(flag), any());
- assertWithMessage("Config flag %s is supported", flag).that(isSupported).isFalse();
+ mExpect.withMessage("Config flag %s is supported", flag).that(isSupported).isFalse();
}
@Test
@@ -697,7 +728,7 @@
boolean isSupported = mTunerSessions[0].isConfigFlagSupported(flag);
verify(mHalTunerSessionMock).isConfigFlagSet(eq(flag), any());
- assertWithMessage("Config flag %s is supported", flag).that(isSupported).isTrue();
+ mExpect.withMessage("Config flag %s is supported", flag).that(isSupported).isTrue();
}
@Test
@@ -709,7 +740,7 @@
mTunerSessions[0].setConfigFlag(flag, /* value= */ true);
});
- assertWithMessage("Exception for setting unsupported flag %s", flag)
+ mExpect.withMessage("Exception for setting unsupported flag %s", flag)
.that(thrown).hasMessageThat().contains("setConfigFlag: NOT_SUPPORTED");
}
@@ -755,7 +786,7 @@
mTunerSessions[0].isConfigFlagSet(flag);
});
- assertWithMessage("Exception for checking if unsupported flag %s is set", flag)
+ mExpect.withMessage("Exception for checking if unsupported flag %s is set", flag)
.that(thrown).hasMessageThat().contains("isConfigFlagSet: NOT_SUPPORTED");
}
@@ -768,7 +799,7 @@
boolean isSet = mTunerSessions[0].isConfigFlagSet(flag);
- assertWithMessage("Config flag %s is set", flag)
+ mExpect.withMessage("Config flag %s is set", flag)
.that(isSet).isEqualTo(expectedConfigFlagValue);
}
@@ -782,7 +813,7 @@
mTunerSessions[0].isConfigFlagSet(flag);
});
- assertWithMessage("Exception for checking config flag when HAL throws remote exception")
+ mExpect.withMessage("Exception for checking config flag when HAL throws remote exception")
.that(thrown).hasMessageThat().contains("Failed to check flag");
}
@@ -822,7 +853,7 @@
mTunerSessions[0].setParameters(parametersSet);
});
- assertWithMessage("Exception for setting parameters when HAL throws remote exception")
+ mExpect.withMessage("Exception for setting parameters when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -848,7 +879,7 @@
mTunerSessions[0].getParameters(parameterKeys);
});
- assertWithMessage("Exception for getting parameters when HAL throws remote exception")
+ mExpect.withMessage("Exception for getting parameters when HAL throws remote exception")
.that(thrown).hasMessageThat().contains(exceptionMessage);
}
@@ -894,6 +925,36 @@
}
}
+ @Test
+ public void openSession_withNonNullAntennaState() throws Exception {
+ boolean antennaConnected = false;
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+ openAidlClients(/* numClients= */ 1);
+ mHalTunerCallback.onAntennaStateChange(antennaConnected);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onAntennaState(antennaConnected);
+ }
+
+ @Test
+ public void openSession_withNonNullCurrentProgramInfo() throws Exception {
+ openAidlClients(/* numClients= */ 1);
+ ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+ RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel,
+ SIGNAL_QUALITY);
+ mTunerSessions[0].tune(initialSel);
+ verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ android.hardware.radio.ITunerCallback callback =
+ mock(android.hardware.radio.ITunerCallback.class);
+
+ mRadioModule.openSession(callback);
+
+ verify(callback, CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+ }
+
private void openAidlClients(int numClients) throws Exception {
mAidlTunerCallbackMocks = new android.hardware.radio.ITunerCallback[numClients];
mTunerSessions = new TunerSession[numClients];
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 16c77d0..ecf4720 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -24,6 +24,7 @@
import android.app.compat.CompatChanges;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
+import android.os.SystemProperties;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -50,6 +51,11 @@
private static final String TAG = "WindowExtensionsImpl";
/**
+ * The value of the system property that indicates no override is set.
+ */
+ private static final int NO_LEVEL_OVERRIDE = -1;
+
+ /**
* The min version of the WM Extensions that must be supported in the current platform version.
*/
@VisibleForTesting
@@ -66,14 +72,30 @@
WindowExtensionsImpl() {
mIsActivityEmbeddingEnabled = isActivityEmbeddingEnabled();
- Log.i(TAG, "Initializing Window Extensions, vendor API level=" + mVersion
- + ", activity embedding enabled=" + mIsActivityEmbeddingEnabled);
+
+ Log.i(TAG, generateLogMessage());
+ }
+
+ private String generateLogMessage() {
+ final StringBuilder logBuilder = new StringBuilder("Initializing Window Extensions, "
+ + "vendor API level=" + mVersion);
+ final int levelOverride = getLevelOverride();
+ if (levelOverride != NO_LEVEL_OVERRIDE) {
+ logBuilder.append(", override to ").append(levelOverride);
+ }
+ logBuilder.append(", activity embedding enabled=").append(mIsActivityEmbeddingEnabled);
+ return logBuilder.toString();
}
// TODO(b/241126279) Introduce constants to better version functionality
@Override
public int getVendorApiLevel() {
- return mVersion;
+ final int levelOverride = getLevelOverride();
+ return (levelOverride != NO_LEVEL_OVERRIDE) ? levelOverride : mVersion;
+ }
+
+ private int getLevelOverride() {
+ return SystemProperties.getInt("persist.wm.debug.ext_version_override", NO_LEVEL_OVERRIDE);
}
@NonNull
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index aafb2e1..150a6e6 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -84,7 +84,7 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bublina"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Spravovat"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bublina byla zavřena."</string>
- <string name="restart_button_description" msgid="4564728020654658478">"Klepnutím tuto aplikaci kvůli lepšímu zobrazení restartujete"</string>
+ <string name="restart_button_description" msgid="4564728020654658478">"Klepnutím tuto aplikaci restartujete kvůli lepšímu zobrazení"</string>
<string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Změnit v Nastavení poměr stran této aplikace"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Změnit poměr stran"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 9f03d8b..6005be4 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -85,7 +85,7 @@
<string name="manage_bubbles_text" msgid="7730624269650594419">"Administrer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Boblen er avvist."</string>
<string name="restart_button_description" msgid="4564728020654658478">"Trykk for å starte denne appen på nytt og få en bedre visning"</string>
- <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Endre høyde/bredde-forholdet for denne appen i innstillingene"</string>
+ <string name="user_aspect_ratio_settings_button_hint" msgid="734835849600713016">"Endre høyde/bredde-forholdet for denne appen i Innstillinger"</string>
<string name="user_aspect_ratio_settings_button_description" msgid="4315566801697411684">"Endre høyde/bredde-forholdet"</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du kameraproblemer?\nTrykk for å tilpasse"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index a7da07d..972dce5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -209,7 +209,7 @@
@Override
public void onDismissBubble(Bubble bubble) {
- mManager.dismissBubble(bubble, Bubbles.DISMISS_USER_REMOVED);
+ mManager.dismissBubble(bubble, Bubbles.DISMISS_USER_GESTURE);
}
});
mHandleView.setOnClickListener(view -> {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 57e95d6..f4ac5f2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -538,8 +538,10 @@
@Override
public void onAnimationStart(Animator animation) {
+ ValueAnimator valueAnimator = (ValueAnimator) animation;
+ float value = (float) valueAnimator.getAnimatedValue();
SurfaceControl.Transaction t = mTransactionPool.acquire();
- t.setPosition(mImeSourceControl.getLeash(), x, startY);
+ t.setPosition(mImeSourceControl.getLeash(), x, value);
if (DEBUG) {
Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
+ imeTop(hiddenY) + "->" + imeTop(shownY)
@@ -549,7 +551,7 @@
imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t);
mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0;
final float alpha = (mAnimateAlpha || isFloating)
- ? (startY - hiddenY) / (shownY - hiddenY)
+ ? (value - hiddenY) / (shownY - hiddenY)
: 1.f;
t.setAlpha(mImeSourceControl.getLeash(), alpha);
if (mAnimationDirection == DIRECTION_SHOW) {
@@ -560,7 +562,7 @@
if (DEBUG_IME_VISIBILITY) {
EventLog.writeEvent(IMF_IME_REMOTE_ANIM_START,
mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
- mDisplayId, mAnimationDirection, alpha, startY , endY,
+ mDisplayId, mAnimationDirection, alpha, value, endY,
Objects.toString(mImeSourceControl.getLeash()),
Objects.toString(mImeSourceControl.getInsetsHint()),
Objects.toString(mImeSourceControl.getSurfacePosition()),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 991fbaf..609e5af 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -87,6 +87,7 @@
import com.android.wm.shell.recents.RecentTasks;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.recents.RecentsTransitionHandler;
+import com.android.wm.shell.recents.TaskStackTransitionObserver;
import com.android.wm.shell.shared.DesktopModeStatus;
import com.android.wm.shell.shared.ShellTransitions;
import com.android.wm.shell.shared.annotations.ShellAnimationThread;
@@ -619,12 +620,13 @@
TaskStackListenerImpl taskStackListener,
ActivityTaskManager activityTaskManager,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ TaskStackTransitionObserver taskStackTransitionObserver,
@ShellMainThread ShellExecutor mainExecutor
) {
return Optional.ofNullable(
RecentTasksController.create(context, shellInit, shellController,
shellCommandHandler, taskStackListener, activityTaskManager,
- desktopModeTaskRepository, mainExecutor));
+ desktopModeTaskRepository, taskStackTransitionObserver, mainExecutor));
}
@BindsOptionalOf
@@ -924,6 +926,19 @@
}
//
+ // Task Stack
+ //
+
+ @WMSingleton
+ @Provides
+ static TaskStackTransitionObserver provideTaskStackTransitionObserver(
+ Lazy<Transitions> transitions,
+ ShellInit shellInit
+ ) {
+ return new TaskStackTransitionObserver(transitions, shellInit);
+ }
+
+ //
// Misc
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 12bbd51..87bd840 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -121,9 +121,9 @@
*/
@Module(
includes = {
- WMShellBaseModule.class,
- PipModule.class,
- ShellBackAnimationModule.class,
+ WMShellBaseModule.class,
+ PipModule.class,
+ ShellBackAnimationModule.class,
})
public abstract class WMShellModule {
@@ -664,7 +664,8 @@
@Provides
static Object provideIndependentShellComponentsToCreate(
DragAndDropController dragAndDropController,
- Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional) {
+ Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional
+ ) {
return new Object();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
index 62d195e..245829e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl
@@ -42,4 +42,7 @@
* Called when a running task changes.
*/
void onRunningTaskChanged(in RunningTaskInfo taskInfo);
-}
+
+ /** A task has moved to front. */
+ oneway void onTaskMovedToFront(in RunningTaskInfo taskInfo);
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/OWNERS
new file mode 100644
index 0000000..452644b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/OWNERS
@@ -0,0 +1,6 @@
+# WM shell sub-module task stack owners
+uysalorhan@google.com
+samcackett@google.com
+alexchau@google.com
+silvajordan@google.com
+uwaisashraf@google.com
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 9d16246..03c8cf8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.FEATURE_PC;
import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+import static com.android.window.flags.Flags.enableTaskStackObserverInShell;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
import android.app.ActivityManager;
@@ -57,6 +58,7 @@
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.SplitBounds;
@@ -73,7 +75,8 @@
* Manages the recent task list from the system, caching it as necessary.
*/
public class RecentTasksController implements TaskStackListenerCallback,
- RemoteCallable<RecentTasksController>, DesktopModeTaskRepository.ActiveTasksListener {
+ RemoteCallable<RecentTasksController>, DesktopModeTaskRepository.ActiveTasksListener,
+ TaskStackTransitionObserver.TaskStackTransitionObserverListener {
private static final String TAG = RecentTasksController.class.getSimpleName();
private final Context mContext;
@@ -84,6 +87,7 @@
private final TaskStackListenerImpl mTaskStackListener;
private final RecentTasksImpl mImpl = new RecentTasksImpl();
private final ActivityTaskManager mActivityTaskManager;
+ private final TaskStackTransitionObserver mTaskStackTransitionObserver;
private RecentsTransitionHandler mTransitionHandler = null;
private IRecentTasksListener mListener;
private final boolean mPcFeatureEnabled;
@@ -112,13 +116,15 @@
TaskStackListenerImpl taskStackListener,
ActivityTaskManager activityTaskManager,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ TaskStackTransitionObserver taskStackTransitionObserver,
@ShellMainThread ShellExecutor mainExecutor
) {
if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
return null;
}
return new RecentTasksController(context, shellInit, shellController, shellCommandHandler,
- taskStackListener, activityTaskManager, desktopModeTaskRepository, mainExecutor);
+ taskStackListener, activityTaskManager, desktopModeTaskRepository,
+ taskStackTransitionObserver, mainExecutor);
}
RecentTasksController(Context context,
@@ -128,6 +134,7 @@
TaskStackListenerImpl taskStackListener,
ActivityTaskManager activityTaskManager,
Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
+ TaskStackTransitionObserver taskStackTransitionObserver,
ShellExecutor mainExecutor) {
mContext = context;
mShellController = shellController;
@@ -136,6 +143,7 @@
mPcFeatureEnabled = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
mTaskStackListener = taskStackListener;
mDesktopModeTaskRepository = desktopModeTaskRepository;
+ mTaskStackTransitionObserver = taskStackTransitionObserver;
mMainExecutor = mainExecutor;
shellInit.addInitCallback(this::onInit, this);
}
@@ -154,6 +162,10 @@
mShellCommandHandler.addDumpCallback(this::dump, this);
mTaskStackListener.addListener(this);
mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTaskListener(this));
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this,
+ mMainExecutor);
+ }
}
void setTransitionHandler(RecentsTransitionHandler handler) {
@@ -267,6 +279,12 @@
notifyRecentTasksChanged();
}
+ @Override
+ public void onTaskMovedToFrontThroughTransition(
+ ActivityManager.RunningTaskInfo runningTaskInfo) {
+ notifyTaskMovedToFront(runningTaskInfo);
+ }
+
@VisibleForTesting
void notifyRecentTasksChanged() {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Notify recent tasks changed");
@@ -328,6 +346,19 @@
}
}
+ private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mListener == null
+ || !enableTaskStackObserverInShell()
+ || taskInfo.realActivity == null) {
+ return;
+ }
+ try {
+ mListener.onTaskMovedToFront(taskInfo);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed call onTaskMovedToFront", e);
+ }
+ }
+
private boolean shouldEnableRunningTasksForDesktopMode() {
return mPcFeatureEnabled
|| (DesktopModeStatus.canEnterDesktopMode(mContext)
@@ -464,6 +495,7 @@
}
return null;
}
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
@@ -547,6 +579,11 @@
public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
mListener.call(l -> l.onRunningTaskChanged(taskInfo));
}
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ mListener.call(l -> l.onTaskMovedToFront(taskInfo));
+ }
};
public IRecentTasksImpl(RecentTasksController controller) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
new file mode 100644
index 0000000..7c5f10a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.recents
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.os.IBinder
+import android.util.ArrayMap
+import android.view.SurfaceControl
+import android.view.WindowManager
+import android.window.TransitionInfo
+import com.android.window.flags.Flags.enableTaskStackObserverInShell
+import com.android.wm.shell.shared.TransitionUtil
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.Transitions
+import dagger.Lazy
+import java.util.concurrent.Executor
+
+/**
+ * A [Transitions.TransitionObserver] that observes shell transitions and sends updates to listeners
+ * about task stack changes.
+ *
+ * TODO(346588978) Move split/pip signals here as well so that launcher don't need to handle it
+ */
+class TaskStackTransitionObserver(
+ private val transitions: Lazy<Transitions>,
+ shellInit: ShellInit
+) : Transitions.TransitionObserver {
+
+ private val transitionToTransitionChanges: MutableMap<IBinder, TransitionChanges> =
+ mutableMapOf()
+ private val taskStackTransitionObserverListeners =
+ ArrayMap<TaskStackTransitionObserverListener, Executor>()
+
+ init {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ shellInit.addInitCallback(::onInit, this)
+ }
+ }
+
+ fun onInit() {
+ transitions.get().registerObserver(this)
+ }
+
+ override fun onTransitionReady(
+ transition: IBinder,
+ info: TransitionInfo,
+ startTransaction: SurfaceControl.Transaction,
+ finishTransaction: SurfaceControl.Transaction
+ ) {
+ if (enableTaskStackObserverInShell()) {
+ val taskInfoList = mutableListOf<RunningTaskInfo>()
+ val transitionTypeList = mutableListOf<Int>()
+
+ for (change in info.changes) {
+ if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) {
+ continue
+ }
+
+ val taskInfo = change.taskInfo
+ if (taskInfo == null || taskInfo.taskId == -1) {
+ continue
+ }
+
+ if (change.mode == WindowManager.TRANSIT_OPEN) {
+ change.taskInfo?.let { taskInfoList.add(it) }
+ transitionTypeList.add(change.mode)
+ }
+ }
+ transitionToTransitionChanges.put(
+ transition,
+ TransitionChanges(taskInfoList, transitionTypeList)
+ )
+ }
+ }
+
+ override fun onTransitionStarting(transition: IBinder) {}
+
+ override fun onTransitionMerged(merged: IBinder, playing: IBinder) {}
+
+ override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
+ val taskInfoList =
+ transitionToTransitionChanges.getOrDefault(transition, TransitionChanges()).taskInfoList
+ val typeList =
+ transitionToTransitionChanges
+ .getOrDefault(transition, TransitionChanges())
+ .transitionTypeList
+ transitionToTransitionChanges.remove(transition)
+
+ for ((index, taskInfo) in taskInfoList.withIndex()) {
+ if (
+ TransitionUtil.isOpeningType(typeList[index]) &&
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
+ ) {
+ notifyTaskStackTransitionObserverListeners(taskInfo)
+ }
+ }
+ }
+
+ fun addTaskStackTransitionObserverListener(
+ taskStackTransitionObserverListener: TaskStackTransitionObserverListener,
+ executor: Executor
+ ) {
+ taskStackTransitionObserverListeners[taskStackTransitionObserverListener] = executor
+ }
+
+ fun removeTaskStackTransitionObserverListener(
+ taskStackTransitionObserverListener: TaskStackTransitionObserverListener
+ ) {
+ taskStackTransitionObserverListeners.remove(taskStackTransitionObserverListener)
+ }
+
+ private fun notifyTaskStackTransitionObserverListeners(taskInfo: RunningTaskInfo) {
+ taskStackTransitionObserverListeners.forEach { (listener, executor) ->
+ executor.execute { listener.onTaskMovedToFrontThroughTransition(taskInfo) }
+ }
+ }
+
+ /** Listener to use to get updates regarding task stack from this observer */
+ interface TaskStackTransitionObserverListener {
+ /** Called when a task is moved to front. */
+ fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {}
+ }
+
+ private data class TransitionChanges(
+ val taskInfoList: MutableList<RunningTaskInfo> = ArrayList(),
+ val transitionTypeList: MutableList<Int> = ArrayList()
+ )
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
index f813b0d..0fe7a16b 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/Android.bp
@@ -65,9 +65,11 @@
android_test {
name: "WMShellFlickerTestsSplitScreenGroup2",
+ defaults: ["WMShellFlickerTestsDefault"],
manifest: "AndroidManifest.xml",
package_name: "com.android.wm.shell.flicker.splitscreen",
instrumentation_target_package: "com.android.wm.shell.flicker.splitscreen",
+ test_config_template: "AndroidTestTemplate.xml",
srcs: [
":WMShellFlickerTestsSplitScreenBase-src",
":WMShellFlickerTestsSplitScreenGroup2-src",
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
new file mode 100644
index 0000000..dad5db9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen
+
+import android.platform.test.annotations.Presubmit
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import androidx.test.filters.RequiresDevice
+import com.android.wm.shell.flicker.splitscreen.benchmark.MultipleShowImeRequestsInSplitScreenBenchmark
+import com.android.wm.shell.flicker.utils.ICommonAssertions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switch between two split pairs.
+ *
+ * To run this test: `atest WMShellFlickerTestsSplitScreenGroup2:MultipleShowImeRequestsInSplitScreen`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class MultipleShowImeRequestsInSplitScreen(override val flicker: LegacyFlickerTest) :
+ MultipleShowImeRequestsInSplitScreenBenchmark(flicker), ICommonAssertions {
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ defaultSetup(this)
+ defaultTeardown(this)
+ thisTransition(this)
+ }
+
+ @Presubmit
+ @Test
+ fun imeLayerAlwaysVisible() =
+ flicker.assertLayers {
+ this.isVisible(ComponentNameMatcher.IME)
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_0)
+ )
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index 9045364..d349988 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -47,7 +47,7 @@
* To run this test: `atest WMShellFlickerTestsSplitScreen:UnlockKeyguardToSplitScreen`
*/
@RequiresDevice
-@Postsubmit
+@FlakyTest(bugId = 293578017)
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -61,7 +61,6 @@
}
@Test
- @FlakyTest(bugId = 293578017)
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/MultipleShowImeRequestsInSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/MultipleShowImeRequestsInSplitScreenBenchmark.kt
new file mode 100644
index 0000000..2492531
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/MultipleShowImeRequestsInSplitScreenBenchmark.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen.benchmark
+
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+abstract class MultipleShowImeRequestsInSplitScreenBenchmark(
+ override val flicker: LegacyFlickerTest
+) : SplitScreenBase(flicker) {
+ override val primaryApp = ImeAppHelper(instrumentation)
+ override val defaultTeardown: FlickerBuilder.() -> Unit
+ get() = {
+ teardown {
+ primaryApp.closeIME(wmHelper)
+ super.defaultTeardown
+ }
+ }
+
+ protected val thisTransition: FlickerBuilder.() -> Unit
+ get() = {
+ setup {
+ SplitScreenUtils.enterSplit(
+ wmHelper,
+ tapl,
+ device,
+ primaryApp,
+ secondaryApp,
+ flicker.scenario.startRotation
+ )
+ // initially open the IME
+ primaryApp.openIME(wmHelper)
+ }
+ transitions {
+ for (i in 1..OPEN_IME_COUNT) {
+ primaryApp.openIME(wmHelper)
+ }
+ }
+ }
+
+ companion object {
+ const val OPEN_IME_COUNT = 30
+
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
index 4b10603..51074f6 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
@@ -25,7 +25,7 @@
abstract class SplitScreenBase(flicker: LegacyFlickerTest) : BaseBenchmarkTest(flicker) {
protected val context: Context = instrumentation.context
- protected val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
+ protected open val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
protected val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
protected open val defaultSetup: FlickerBuilder.() -> Unit = {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
index 5f6132a..0d3cd10 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt
@@ -40,14 +40,14 @@
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG
-import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_ENTER_DESKTOP_FROM_UNKNOWN
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG
+import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN
import com.android.wm.shell.shared.DesktopModeStatus
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.TransitionInfoBuilder
@@ -78,409 +78,397 @@
@RunWith(AndroidTestingRunner::class)
class DesktopModeLoggerTransitionObserverTest {
- @JvmField
- @Rule
- val extendedMockitoRule =
- ExtendedMockitoRule.Builder(this)
- .mockStatic(DesktopModeEventLogger::class.java)
- .mockStatic(DesktopModeStatus::class.java)
- .build()!!
+ @JvmField
+ @Rule
+ val extendedMockitoRule =
+ ExtendedMockitoRule.Builder(this)
+ .mockStatic(DesktopModeEventLogger::class.java)
+ .mockStatic(DesktopModeStatus::class.java)
+ .build()!!
- @Mock lateinit var testExecutor: ShellExecutor
- @Mock private lateinit var mockShellInit: ShellInit
- @Mock private lateinit var transitions: Transitions
- @Mock private lateinit var context: Context
+ @Mock lateinit var testExecutor: ShellExecutor
+ @Mock private lateinit var mockShellInit: ShellInit
+ @Mock private lateinit var transitions: Transitions
+ @Mock private lateinit var context: Context
- private lateinit var transitionObserver: DesktopModeLoggerTransitionObserver
- private lateinit var shellInit: ShellInit
- private lateinit var desktopModeEventLogger: DesktopModeEventLogger
+ private lateinit var transitionObserver: DesktopModeLoggerTransitionObserver
+ private lateinit var shellInit: ShellInit
+ private lateinit var desktopModeEventLogger: DesktopModeEventLogger
- @Before
- fun setup() {
- doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(any()) }
- shellInit = Mockito.spy(ShellInit(testExecutor))
- desktopModeEventLogger = mock(DesktopModeEventLogger::class.java)
+ @Before
+ fun setup() {
+ doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(any()) }
+ shellInit = Mockito.spy(ShellInit(testExecutor))
+ desktopModeEventLogger = mock(DesktopModeEventLogger::class.java)
- transitionObserver =
- DesktopModeLoggerTransitionObserver(
- context,
- mockShellInit,
- transitions,
- desktopModeEventLogger
- )
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
- verify(mockShellInit)
- .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
- initRunnableCaptor.value.run()
- } else {
- transitionObserver.onInit()
- }
+ transitionObserver =
+ DesktopModeLoggerTransitionObserver(
+ context, mockShellInit, transitions, desktopModeEventLogger)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+ verify(mockShellInit).addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+ initRunnableCaptor.value.run()
+ } else {
+ transitionObserver.onInit()
+ }
+ }
+
+ @Test
+ fun testRegistersObserverAtInit() {
+ verify(transitions).registerObserver(same(transitionObserver))
+ }
+
+ @Test
+ fun transitOpen_notFreeformWindow_doesNotLogTaskAddedOrSessionEnter() {
+ val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
+ verify(desktopModeEventLogger, never()).logTaskAdded(any(), any())
+ }
+
+ @Test
+ fun transitOpen_logTaskAddedAndEnterReasonAppFreeformIntent() {
+ val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FREEFORM_INTENT))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEndDragToDesktop_logTaskAddedAndEnterReasonAppHandleDrag() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ // task change is finalised when drag ends
+ val transitionInfo =
+ TransitionInfoBuilder(Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_DRAG))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopByButtonTap_logTaskAddedAndEnterReasonButtonTap() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_MENU_BUTTON))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopFromAppFromOverview_logTaskAddedAndEnterReasonUnknown() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FROM_OVERVIEW))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopFromKeyboardShortcut_logTaskAddedAndEnterReasonKeyboardShortcut() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT, 0)
+ .addChange(change)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.KEYBOARD_SHORTCUT_ENTER))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitEnterDesktopFromUnknown_logTaskAddedAndEnterReasonUnknown() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_UNKNOWN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.UNKNOWN_ENTER))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitWake_logTaskAddedAndEnterReasonScreenOn() {
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_WAKE, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ val sessionId = transitionObserver.getLoggerSessionId()
+
+ assertThat(sessionId).isNotNull()
+ verify(desktopModeEventLogger, times(1))
+ .logSessionEnter(eq(sessionId!!), eq(EnterReason.SCREEN_ON))
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verifyZeroInteractions(desktopModeEventLogger)
+ }
+
+ @Test
+ fun transitSleep_logTaskAddedAndExitReasonScreenOff_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_SLEEP).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.SCREEN_OFF))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopTaskDrag_logTaskRemovedAndExitReasonDragToExit_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.DRAG_TO_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopAppHandleButton_logTaskRemovedAndExitReasonButton_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON)
+ .addChange(change)
+ .build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.APP_HANDLE_MENU_BUTTON_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopUsingKeyboard_logTaskRemovedAndExitReasonKeyboard_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.KEYBOARD_SHORTCUT_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitExitDesktopUnknown_logTaskRemovedAndExitReasonUnknown_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // window mode changing from FREEFORM to FULLSCREEN
+ val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.UNKNOWN_EXIT))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitToFrontWithFlagRecents_logTaskRemovedAndExitReasonOverview_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // recents transition
+ val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo =
+ TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun transitClose_logTaskRemovedAndExitReasonTaskFinished_sessionIdNull() {
+ val sessionId = 1
+ // add a freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // task closing
+ val change = createChange(TRANSIT_CLOSE, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.TASK_FINISHED))
+ verifyZeroInteractions(desktopModeEventLogger)
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+ }
+
+ @Test
+ fun sessionExitByRecents_cancelledAnimation_sessionRestored() {
+ val sessionId = 1
+ // add a freeform task to an existing session
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // recents transition sent freeform window to back
+ val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ val transitionInfo1 =
+ TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS).addChange(change).build()
+ callOnTransitionReady(transitionInfo1)
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, times(1))
+ .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
+ assertThat(transitionObserver.getLoggerSessionId()).isNull()
+
+ val transitionInfo2 = TransitionInfoBuilder(TRANSIT_NONE).build()
+ callOnTransitionReady(transitionInfo2)
+
+ verify(desktopModeEventLogger, times(1)).logSessionEnter(any(), any())
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(any(), any())
+ }
+
+ @Test
+ fun sessionAlreadyStarted_newFreeformTaskAdded_logsTaskAdded() {
+ val sessionId = 1
+ // add an existing freeform task
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // new freeform task added
+ val change = createChange(TRANSIT_OPEN, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
+ verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
+ }
+
+ @Test
+ fun sessionAlreadyStarted_freeformTaskRemoved_logsTaskRemoved() {
+ val sessionId = 1
+ // add two existing freeform tasks
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
+ transitionObserver.addTaskInfosToCachedMap(createTaskInfo(2, WINDOWING_MODE_FREEFORM))
+ transitionObserver.setLoggerSessionId(sessionId)
+
+ // new freeform task added
+ val change = createChange(TRANSIT_CLOSE, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
+ val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build()
+ callOnTransitionReady(transitionInfo)
+
+ verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
+ verify(desktopModeEventLogger, never()).logSessionExit(any(), any())
+ }
+
+ /** Simulate calling the onTransitionReady() method */
+ private fun callOnTransitionReady(transitionInfo: TransitionInfo) {
+ val transition = mock(IBinder::class.java)
+ val startT = mock(SurfaceControl.Transaction::class.java)
+ val finishT = mock(SurfaceControl.Transaction::class.java)
+
+ transitionObserver.onTransitionReady(transition, transitionInfo, startT, finishT)
+ }
+
+ companion object {
+ fun createTaskInfo(taskId: Int, windowMode: Int): ActivityManager.RunningTaskInfo {
+ val taskInfo = ActivityManager.RunningTaskInfo()
+ taskInfo.taskId = taskId
+ taskInfo.configuration.windowConfiguration.windowingMode = windowMode
+
+ return taskInfo
}
- @Test
- fun testRegistersObserverAtInit() {
- verify(transitions).registerObserver(same(transitionObserver))
+ fun createChange(mode: Int, taskInfo: ActivityManager.RunningTaskInfo): Change {
+ val change =
+ Change(
+ WindowContainerToken(mock(IWindowContainerToken::class.java)),
+ mock(SurfaceControl::class.java))
+ change.mode = mode
+ change.taskInfo = taskInfo
+ return change
}
-
- @Test
- fun transitOpen_notFreeformWindow_doesNotLogTaskAddedOrSessionEnter() {
- val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
- verify(desktopModeEventLogger, never()).logTaskAdded(any(), any())
- }
-
- @Test
- fun transitOpen_logTaskAddedAndEnterReasonAppFreeformIntent() {
- val change = createChange(TRANSIT_OPEN, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FREEFORM_INTENT))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEndDragToDesktop_logTaskAddedAndEnterReasonAppHandleDrag() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- // task change is finalised when drag ends
- val transitionInfo =
- TransitionInfoBuilder(Transitions.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_DRAG))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEnterDesktopByButtonTap_logTaskAddedAndEnterReasonButtonTap() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_HANDLE_MENU_BUTTON, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_HANDLE_MENU_BUTTON))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEnterDesktopFromAppFromOverview_logTaskAddedAndEnterReasonUnknown() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_APP_FROM_OVERVIEW, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.APP_FROM_OVERVIEW))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEnterDesktopFromKeyboardShortcut_logTaskAddedAndEnterReasonKeyboardShortcut() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT, 0)
- .addChange(change)
- .build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.KEYBOARD_SHORTCUT_ENTER))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitEnterDesktopFromUnknown_logTaskAddedAndEnterReasonUnknown() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_ENTER_DESKTOP_FROM_UNKNOWN, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.UNKNOWN_ENTER))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitWake_logTaskAddedAndEnterReasonScreenOn() {
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_WAKE, 0).addChange(change).build()
-
- callOnTransitionReady(transitionInfo)
- val sessionId = transitionObserver.getLoggerSessionId()
-
- assertThat(sessionId).isNotNull()
- verify(desktopModeEventLogger, times(1))
- .logSessionEnter(eq(sessionId!!), eq(EnterReason.SCREEN_ON))
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verifyZeroInteractions(desktopModeEventLogger)
- }
-
- @Test
- fun transitSleep_logTaskAddedAndExitReasonScreenOff_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- val transitionInfo = TransitionInfoBuilder(TRANSIT_SLEEP).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.SCREEN_OFF))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopTaskDrag_logTaskRemovedAndExitReasonDragToExit_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_TASK_DRAG).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.DRAG_TO_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopAppHandleButton_logTaskRemovedAndExitReasonButton_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_HANDLE_MENU_BUTTON)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.APP_HANDLE_MENU_BUTTON_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopUsingKeyboard_logTaskRemovedAndExitReasonKeyboard_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.KEYBOARD_SHORTCUT_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitExitDesktopUnknown_logTaskRemovedAndExitReasonUnknown_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // window mode changing from FREEFORM to FULLSCREEN
- val change = createChange(TRANSIT_TO_FRONT, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_EXIT_DESKTOP_MODE_UNKNOWN).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.UNKNOWN_EXIT))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitToFrontWithFlagRecents_logTaskRemovedAndExitReasonOverview_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // recents transition
- val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo =
- TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun transitClose_logTaskRemovedAndExitReasonTaskFinished_sessionIdNull() {
- val sessionId = 1
- // add a freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // task closing
- val change = createChange(TRANSIT_CLOSE, createTaskInfo(1, WINDOWING_MODE_FULLSCREEN))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.TASK_FINISHED))
- verifyZeroInteractions(desktopModeEventLogger)
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
- }
-
- @Test
- fun sessionExitByRecents_cancelledAnimation_sessionRestored() {
- val sessionId = 1
- // add a freeform task to an existing session
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // recents transition sent freeform window to back
- val change = createChange(TRANSIT_TO_BACK, createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- val transitionInfo1 =
- TransitionInfoBuilder(TRANSIT_TO_FRONT, TRANSIT_FLAG_IS_RECENTS)
- .addChange(change)
- .build()
- callOnTransitionReady(transitionInfo1)
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, times(1))
- .logSessionExit(eq(sessionId), eq(ExitReason.RETURN_HOME_OR_OVERVIEW))
- assertThat(transitionObserver.getLoggerSessionId()).isNull()
-
- val transitionInfo2 = TransitionInfoBuilder(TRANSIT_NONE).build()
- callOnTransitionReady(transitionInfo2)
-
- verify(desktopModeEventLogger, times(1)).logSessionEnter(any(), any())
- verify(desktopModeEventLogger, times(1)).logTaskAdded(any(), any())
- }
-
- @Test
- fun sessionAlreadyStarted_newFreeformTaskAdded_logsTaskAdded() {
- val sessionId = 1
- // add an existing freeform task
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // new freeform task added
- val change = createChange(TRANSIT_OPEN, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskAdded(eq(sessionId), any())
- verify(desktopModeEventLogger, never()).logSessionEnter(any(), any())
- }
-
- @Test
- fun sessionAlreadyStarted_freeformTaskRemoved_logsTaskRemoved() {
- val sessionId = 1
- // add two existing freeform tasks
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(1, WINDOWING_MODE_FREEFORM))
- transitionObserver.addTaskInfosToCachedMap(createTaskInfo(2, WINDOWING_MODE_FREEFORM))
- transitionObserver.setLoggerSessionId(sessionId)
-
- // new freeform task added
- val change = createChange(TRANSIT_CLOSE, createTaskInfo(2, WINDOWING_MODE_FREEFORM))
- val transitionInfo = TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build()
- callOnTransitionReady(transitionInfo)
-
- verify(desktopModeEventLogger, times(1)).logTaskRemoved(eq(sessionId), any())
- verify(desktopModeEventLogger, never()).logSessionExit(any(), any())
- }
-
- /** Simulate calling the onTransitionReady() method */
- private fun callOnTransitionReady(transitionInfo: TransitionInfo) {
- val transition = mock(IBinder::class.java)
- val startT = mock(SurfaceControl.Transaction::class.java)
- val finishT = mock(SurfaceControl.Transaction::class.java)
-
- transitionObserver.onTransitionReady(transition, transitionInfo, startT, finishT)
- }
-
- companion object {
- fun createTaskInfo(taskId: Int, windowMode: Int): ActivityManager.RunningTaskInfo {
- val taskInfo = ActivityManager.RunningTaskInfo()
- taskInfo.taskId = taskId
- taskInfo.configuration.windowConfiguration.windowingMode = windowMode
-
- return taskInfo
- }
-
- fun createChange(mode: Int, taskInfo: ActivityManager.RunningTaskInfo): Change {
- val change =
- Change(
- WindowContainerToken(mock(IWindowContainerToken::class.java)),
- mock(SurfaceControl::class.java)
- )
- change.mode = mode
- change.taskInfo = taskInfo
- return change
- }
- }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 56c4cea..e291c0e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -113,6 +113,8 @@
private DisplayInsetsController mDisplayInsetsController;
@Mock
private IRecentTasksListener mRecentTasksListener;
+ @Mock
+ private TaskStackTransitionObserver mTaskStackTransitionObserver;
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -139,7 +141,8 @@
mDisplayInsetsController, mMainExecutor));
mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit,
mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
- Optional.of(mDesktopModeTaskRepository), mMainExecutor);
+ Optional.of(mDesktopModeTaskRepository), mTaskStackTransitionObserver,
+ mMainExecutor);
mRecentTasksController = spy(mRecentTasksControllerReal);
mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController),
@@ -557,6 +560,30 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ public void onTaskMovedToFront_TaskStackObserverEnabled_triggersOnTaskMovedToFront()
+ throws Exception {
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+ ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+
+ mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo);
+
+ verify(mRecentTasksListener).onTaskMovedToFront(taskInfo);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ public void onTaskMovedToFront_TaskStackObserverEnabled_doesNotTriggersOnTaskMovedToFront()
+ throws Exception {
+ mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener);
+ ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10);
+
+ mRecentTasksControllerReal.onTaskMovedToFront(taskInfo);
+
+ verify(mRecentTasksListener, never()).onTaskMovedToFront(any());
+ }
+
+ @Test
public void getNullSplitBoundsNonSplitTask() {
SplitBounds sb = mRecentTasksController.getSplitBoundsForTaskId(3);
assertNull("splitBounds should be null for non-split task", sb);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
new file mode 100644
index 0000000..f959970
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.recents
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.os.IBinder
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import android.view.SurfaceControl
+import android.view.WindowManager
+import android.window.IWindowContainerToken
+import android.window.TransitionInfo
+import android.window.WindowContainerToken
+import androidx.test.filters.SmallTest
+import com.android.window.flags.Flags
+import com.android.wm.shell.TestShellExecutor
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.sysui.ShellInit
+import com.android.wm.shell.transition.TransitionInfoBuilder
+import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.same
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+
+/**
+ * Test class for {@link TaskStackTransitionObserver}
+ *
+ * Usage: atest WMShellUnitTests:TaskStackTransitionObserverTest
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class TaskStackTransitionObserverTest {
+
+ @JvmField @Rule val setFlagsRule = SetFlagsRule()
+
+ @Mock private lateinit var shellInit: ShellInit
+ @Mock lateinit var testExecutor: ShellExecutor
+ @Mock private lateinit var transitionsLazy: Lazy<Transitions>
+ @Mock private lateinit var transitions: Transitions
+ @Mock private lateinit var mockTransitionBinder: IBinder
+
+ private lateinit var transitionObserver: TaskStackTransitionObserver
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ shellInit = Mockito.spy(ShellInit(testExecutor))
+ whenever(transitionsLazy.get()).thenReturn(transitions)
+ transitionObserver = TaskStackTransitionObserver(transitionsLazy, shellInit)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+ verify(shellInit)
+ .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver))
+ initRunnableCaptor.value.run()
+ } else {
+ transitionObserver.onInit()
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun testRegistersObserverAtInit() {
+ verify(transitions).registerObserver(same(transitionObserver))
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun taskCreated_freeformWindow_listenerNotified() {
+ val listener = TestListener()
+ val executor = TestShellExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+ val change =
+ createChange(
+ WindowManager.TRANSIT_OPEN,
+ createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
+ )
+ val transitionInfo =
+ TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ callOnTransitionFinished()
+ executor.flushAll()
+
+ assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(change.taskInfo?.taskId)
+ assertThat(listener.taskInfoToBeNotified.windowingMode)
+ .isEqualTo(change.taskInfo?.windowingMode)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun taskCreated_fullscreenWindow_listenerNotNotified() {
+ val listener = TestListener()
+ val executor = TestShellExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+ val change =
+ createChange(
+ WindowManager.TRANSIT_OPEN,
+ createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN)
+ )
+ val transitionInfo =
+ TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build()
+
+ callOnTransitionReady(transitionInfo)
+ callOnTransitionFinished()
+ executor.flushAll()
+
+ assertThat(listener.taskInfoToBeNotified.taskId).isEqualTo(0)
+ assertThat(listener.taskInfoToBeNotified.windowingMode)
+ .isEqualTo(WindowConfiguration.WINDOWING_MODE_UNDEFINED)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL)
+ fun taskCreated_freeformWindowOnTopOfFreeform_listenerNotified() {
+ val listener = TestListener()
+ val executor = TestShellExecutor()
+ transitionObserver.addTaskStackTransitionObserverListener(listener, executor)
+ val freeformOpenChange =
+ createChange(
+ WindowManager.TRANSIT_OPEN,
+ createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM)
+ )
+ val freeformReorderChange =
+ createChange(
+ WindowManager.TRANSIT_TO_BACK,
+ createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM)
+ )
+ val transitionInfo =
+ TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0)
+ .addChange(freeformOpenChange)
+ .addChange(freeformReorderChange)
+ .build()
+
+ callOnTransitionReady(transitionInfo)
+ callOnTransitionFinished()
+ executor.flushAll()
+
+ assertThat(listener.taskInfoToBeNotified.taskId)
+ .isEqualTo(freeformOpenChange.taskInfo?.taskId)
+ assertThat(listener.taskInfoToBeNotified.windowingMode)
+ .isEqualTo(freeformOpenChange.taskInfo?.windowingMode)
+ }
+
+ class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener {
+ var taskInfoToBeNotified = ActivityManager.RunningTaskInfo()
+
+ override fun onTaskMovedToFrontThroughTransition(
+ taskInfo: ActivityManager.RunningTaskInfo
+ ) {
+ taskInfoToBeNotified = taskInfo
+ }
+ }
+
+ /** Simulate calling the onTransitionReady() method */
+ private fun callOnTransitionReady(transitionInfo: TransitionInfo) {
+ val startT = Mockito.mock(SurfaceControl.Transaction::class.java)
+ val finishT = Mockito.mock(SurfaceControl.Transaction::class.java)
+
+ transitionObserver.onTransitionReady(mockTransitionBinder, transitionInfo, startT, finishT)
+ }
+
+ /** Simulate calling the onTransitionFinished() method */
+ private fun callOnTransitionFinished() {
+ transitionObserver.onTransitionFinished(mockTransitionBinder, false)
+ }
+
+ companion object {
+ fun createTaskInfo(taskId: Int, windowingMode: Int): ActivityManager.RunningTaskInfo {
+ val taskInfo = ActivityManager.RunningTaskInfo()
+ taskInfo.taskId = taskId
+ taskInfo.configuration.windowConfiguration.windowingMode = windowingMode
+
+ return taskInfo
+ }
+
+ fun createChange(
+ mode: Int,
+ taskInfo: ActivityManager.RunningTaskInfo
+ ): TransitionInfo.Change {
+ val change =
+ TransitionInfo.Change(
+ WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java)),
+ Mockito.mock(SurfaceControl::class.java)
+ )
+ change.mode = mode
+ change.taskInfo = taskInfo
+ return change
+ }
+ }
+}
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 055ccbc..3375e18c 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -57,7 +57,9 @@
@FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
+ method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
}
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 7150b54..fd77820 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -110,4 +110,6 @@
void registerOemExtensionCallback(INfcOemExtensionCallback callbacks);
void unregisterOemExtensionCallback(INfcOemExtensionCallback callbacks);
void clearPreference();
+ void setScreenState();
+ void checkFirmware();
}
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 1eff58c..f6138a6 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -141,6 +141,34 @@
}
}
+ /**
+ * Get the screen state from system and set it to current screen state.
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public void synchronizeScreenState() {
+ try {
+ NfcAdapter.sService.setScreenState();
+ } catch (RemoteException e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ }
+ }
+
+ /**
+ * Check if the firmware needs updating.
+ *
+ * <p>If an update is needed, a firmware will be triggered when NFC is disabled.
+ */
+ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public void maybeTriggerFirmwareUpdate() {
+ try {
+ NfcAdapter.sService.checkFirmware();
+ } catch (RemoteException e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ }
+ }
+
private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
@Override
public void onTagConnected(boolean connected, Tag tag) throws RemoteException {
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index bc8a969..91385c6 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -48,7 +48,7 @@
<string name="passwords" msgid="5419394230391253816">"senhas"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informações de login"</string>
- <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> em"</string>
+ <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> no"</string>
<string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Criar chave de acesso em outro dispositivo?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Salvar senha em outro dispositivo?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Salvar credenciais de login em outro dispositivo?"</string>
@@ -57,9 +57,9 @@
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="settings" msgid="6536394145760913145">"Configurações"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
- <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
- <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas"</string>
- <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chaves de acesso"</string>
+ <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>) • Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>)"</string>
+ <string name="more_options_usage_passwords" msgid="1632047277723187813">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>)"</string>
+ <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>)"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g> credenciais"</string>
<string name="passkey_before_subtitle" msgid="2448119456208647444">"Chave de acesso"</string>
<string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index bc8a969..91385c6 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -48,7 +48,7 @@
<string name="passwords" msgid="5419394230391253816">"senhas"</string>
<string name="sign_ins" msgid="4710739369149469208">"logins"</string>
<string name="sign_in_info" msgid="2627704710674232328">"informações de login"</string>
- <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> em"</string>
+ <string name="save_credential_to_title" msgid="3172811692275634301">"Salvar <xliff:g id="CREDENTIALTYPES">%1$s</xliff:g> no"</string>
<string name="create_passkey_in_other_device_title" msgid="2360053098931886245">"Criar chave de acesso em outro dispositivo?"</string>
<string name="save_password_on_other_device_title" msgid="5829084591948321207">"Salvar senha em outro dispositivo?"</string>
<string name="save_sign_in_on_other_device_title" msgid="2827990118560134692">"Salvar credenciais de login em outro dispositivo?"</string>
@@ -57,9 +57,9 @@
<string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
<string name="settings" msgid="6536394145760913145">"Configurações"</string>
<string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
- <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
- <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas"</string>
- <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chaves de acesso"</string>
+ <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>) • Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>)"</string>
+ <string name="more_options_usage_passwords" msgid="1632047277723187813">"Senhas (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>)"</string>
+ <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Chaves de acesso (<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>)"</string>
<string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g> credenciais"</string>
<string name="passkey_before_subtitle" msgid="2448119456208647444">"Chave de acesso"</string>
<string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index 1500583..754abb2 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -33,7 +33,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:label="@string/app_name">
<!-- Android V easter egg: Daydream version of Landroid
@@ -41,7 +41,7 @@
<service
android:name=".landroid.DreamUniverse"
android:exported="true"
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:label="@string/v_egg_name"
android:description="@string/dream_description"
android:enabled="false"
@@ -62,7 +62,7 @@
android:name=".landroid.MainActivity"
android:exported="true"
android:label="@string/u_egg_name"
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:configChanges="orientation|screenLayout|screenSize|density"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
<intent-filter>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_adaptive.xml b/packages/EasterEgg/res/drawable/android15_patch_adaptive.xml
new file mode 100644
index 0000000..d949200
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_adaptive.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android15_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android15_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android15_patch_monochrome"/>
+</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_adaptive_background.xml b/packages/EasterEgg/res/drawable/android15_patch_adaptive_background.xml
new file mode 100644
index 0000000..642b30a
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_adaptive_background.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <!-- space -->
+ <path
+ android:pathData="M0,0h108v108h-108z"
+ android:fillColor="#202124"/>
+ <!-- stars -->
+ <group>
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ </group>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_adaptive_foreground.xml b/packages/EasterEgg/res/drawable/android15_patch_adaptive_foreground.xml
new file mode 100644
index 0000000..1100eb7
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_adaptive_foreground.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+
+ <!-- zoomies -->
+ <group>
+ <path
+ android:pathData="M53,42C52.21,50.58 46.46,68.95 32.11,74.63C19.22,79.75 5.77,82.32 1.19,83.19C0.68,83.29 0.28,83.36 0,83.42V108H54H108V83.42C107.72,83.36 107.32,83.29 106.81,83.19C102.23,82.32 88.78,79.75 75.89,74.63C61.54,68.95 55.79,50.58 55,42H54H53Z"
+ android:fillColor="#C6FF00"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M53.25,42C52.88,50.53 50.44,69.01 43.68,74.67C36.91,80.33 32.65,82.86 31.37,83.41L54,102.87L76.63,83.41C75.35,82.86 71.09,80.33 64.32,74.67C57.56,69.01 55.12,50.53 54.75,42H54H53.25Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M54,42m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#ffffff"/>
+ </group>
+ <group>
+ <!-- head! it's like sputnik -->
+ <path
+ android:pathData="M54,94.25m-26.25,0a26.25,26.25 0,1 1,52.5 0a26.25,26.25 0,1 1,-52.5 0"
+ android:fillColor="#34A853"/>
+ <!-- ant -->
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ </group>
+ <!-- spaceship -->
+ <path
+ android:pathData="M54,34C52.34,34 51,35.29 51,36.88V40.44C51,40.75 51.25,41 51.56,41C51.87,41 52.13,40.75 52.13,40.44V39.48C52.13,38.87 52.63,38.37 53.25,38.37H54.75C55.37,38.37 55.87,38.87 55.87,39.48V40.44C55.87,40.75 56.13,41 56.44,41C56.75,41 57,40.75 57,40.44V36.88C57,35.29 55.66,34 54,34H54Z"
+ android:fillColor="#E9F3EB"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/android15_patch_monochrome.xml b/packages/EasterEgg/res/drawable/android15_patch_monochrome.xml
new file mode 100644
index 0000000..a91cc86
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/android15_patch_monochrome.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <path
+ android:pathData="
+ M54,94.25
+ m-26.25,0
+ a26.25,26.25 0,1 1,52.5 0
+ a26.25,26.25 0,1 1,-52.5 0
+ "
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+
+ <path
+ android:pathData="
+ M54,34
+ C52.34,34 51,35.29 51,36.88
+ V40.44
+ C51,40.75 51.25,41 51.56,41
+ C51.87,41 52.13,40.75 52.13,40.44
+ V39.48
+ C52.13,38.87 52.63,38.37 53.25,38.37
+ H54.75
+ C55.37,38.37 55.87,38.87 55.87,39.48
+ V40.44
+ C55.87,40.75 56.13,41 56.44,41
+ C56.75,41 57,40.75 57,40.44
+ V36.88
+ C57,35.29 55.66,34 54,34
+ H54
+ Z
+ "
+ android:fillColor="#34A853"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M54,40V67"
+ android:fillColor="#00000000"
+ android:strokeColor="#40FFFFFF"
+ />
+
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+
+ </group>
+</vector>
diff --git a/packages/PackageInstaller/res/values-pa/strings.xml b/packages/PackageInstaller/res/values-pa/strings.xml
index 1db92a0..80dc889 100644
--- a/packages/PackageInstaller/res/values-pa/strings.xml
+++ b/packages/PackageInstaller/res/values-pa/strings.xml
@@ -63,7 +63,7 @@
<string name="archive_application_text_all_users" msgid="3151229641681672580">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ਕੀ ਇਸ ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="archive_application_text_user" msgid="2586558895535581451">"ਕੀ ਇਸ ਐਪ ਨੂੰ <xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਹੈ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
- <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੀ ਨਿੱਜੀ ਸਪੇਸ ਤੋਂ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
+ <string name="archive_application_text_current_user_private_profile" msgid="1958423158655599132">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੀ ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਤੋਂ ਪੁਰਾਲੇਖਬੱਧ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਤੁਹਾਡਾ ਨਿੱਜੀ ਡਾਟਾ ਰੱਖਿਅਤ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਲਈ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਐਪਲੀਕੇਸ਼ਨ ਅਤੇ ਇਸਦਾ ਡਾਟਾ ਡੀਵਾਈਸ \'ਤੇ "<b>"ਸਾਰੇ"</b>" ਵਰਤੋਂਕਾਰਾਂ ਵੱਲੋਂ ਹਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"ਕੀ ਤੁਸੀਂ ਵਰਤੋਂਕਾਰ <xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ ਇਸ ਐਪ ਨੂੰ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਆਪਣੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਤੋਂ ਅਣਸਥਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
diff --git a/packages/PackageInstaller/res/values-tr/strings.xml b/packages/PackageInstaller/res/values-tr/strings.xml
index 006ad52..e10eb0e 100644
--- a/packages/PackageInstaller/res/values-tr/strings.xml
+++ b/packages/PackageInstaller/res/values-tr/strings.xml
@@ -55,7 +55,7 @@
<string name="user_is_not_allowed_dlg_text" msgid="3468447791330611681">"Geçerli kullanıcının bu yüklemeyi kaldırma izni yok."</string>
<string name="generic_error_dlg_title" msgid="5863195085927067752">"Hata"</string>
<string name="generic_error_dlg_text" msgid="5287861443265795232">"Uygulamanın yüklemesi kaldırılamadı."</string>
- <string name="uninstall_application_title" msgid="4045420072401428123">"Uygulamanın yüklemesini kaldır"</string>
+ <string name="uninstall_application_title" msgid="4045420072401428123">"Uygulamayı kaldır"</string>
<string name="uninstall_update_title" msgid="824411791011583031">"Güncelleme kaldırılsın mı?"</string>
<string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g>, şu uygulamanın bir parçasıdır:"</string>
<string name="uninstall_application_text" msgid="3816830743706143980">"Bu uygulamanın yüklemesini kaldırmak istiyor musunuz?"</string>
diff --git a/packages/PrintSpooler/res/values-as/strings.xml b/packages/PrintSpooler/res/values-as/strings.xml
index 020eac7..950c5c8 100644
--- a/packages/PrintSpooler/res/values-as/strings.xml
+++ b/packages/PrintSpooler/res/values-as/strings.xml
@@ -100,7 +100,7 @@
</string-array>
<string-array name="orientation_labels">
<item msgid="4061931020926489228">"প\'ৰ্ট্ৰেইট"</item>
- <item msgid="3199660090246166812">"লেণ্ডস্কেইপ"</item>
+ <item msgid="3199660090246166812">"লেণ্ডস্কে’প"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"ফাইলত লিখিব পৰা নহ\'ল"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"দুঃখিত, প্ৰিণ্টিঙৰ কাম নহ\'ল। পুনৰ চেষ্টা কৰক।"</string>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
index eb33d57..75e1a18 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pt-rBR/strings.xml
@@ -19,5 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string>
- <string name="settingslib_category_private" msgid="5039276873477591386">"Particular"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Privado"</string>
</resources>
diff --git a/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
index eb33d57..75e1a18 100644
--- a/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
+++ b/packages/SettingsLib/ProfileSelector/res/values-pt/strings.xml
@@ -19,5 +19,5 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="settingslib_category_personal" msgid="1142302328104700620">"Pessoal"</string>
<string name="settingslib_category_work" msgid="4867750733682444676">"Trabalho"</string>
- <string name="settingslib_category_private" msgid="5039276873477591386">"Particular"</string>
+ <string name="settingslib_category_private" msgid="5039276873477591386">"Privado"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index f0fb4df..caeee06 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -710,7 +710,7 @@
<string name="keyboard_layout_default_label" msgid="1997292217218546957">"Standard"</string>
<string name="turn_screen_on_title" msgid="2662312432042116026">"Steuerelement zum Aktivieren des Displays"</string>
<string name="allow_turn_screen_on" msgid="6194845766392742639">"Aktivieren des Displays erlauben"</string>
- <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Einer App erlauben, das Display zu aktivieren. Wenn du diese Erlaubnis erteilst, kann die App jederzeit das Display aktivieren – auch ohne deine explizite Absicht."</string>
+ <string name="allow_turn_screen_on_description" msgid="43834403291575164">"Einer App erlauben, das Display zu aktivieren. Wenn du diese Erlaubnis erteilst, kann die App jederzeit das Display aktivieren – auch ohne dass du dies beabsichtigst."</string>
<string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"<xliff:g id="APP_NAME">%1$s</xliff:g> nicht mehr streamen?"</string>
<string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Wenn du <xliff:g id="SWITCHAPP">%1$s</xliff:g> streamst oder die Ausgabe änderst, wird dein aktueller Stream beendet"</string>
<string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"<xliff:g id="SWITCHAPP">%1$s</xliff:g> streamen"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 1381903..a25e179 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -632,7 +632,7 @@
<string name="profile_info_settings_title" msgid="105699672534365099">"ಪ್ರೊಫೈಲ್ ಮಾಹಿತಿ"</string>
<string name="user_need_lock_message" msgid="4311424336209509301">"ನೀವು ನಿರ್ಬಂಧಿತ ಪ್ರೊಫೈಲ್ ಅನ್ನು ರಚಿಸಬಹುದಾದರ ಮೊದಲು, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ನೀವು ಪರದೆಯ ಲಾಕ್ ಹೊಂದಿಸುವ ಅಗತ್ಯವಿದೆ."</string>
<string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string>
- <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g> ಗೆ ಬದಲಿಸಿ"</string>
+ <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>ಗೆ ಬದಲಿಸಿ"</string>
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="add_user_failed" msgid="4809887794313944872">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು ವಿಫಲವಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 5032e35..1e33f88 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -641,7 +641,7 @@
<string name="edit_user_info_message" msgid="6677556031419002895">"यो डिभाइस प्रयोग गर्ने सबै जना तपाईंले छनौट गर्ने नाम र फोटो देख्न सक्ने छन्।"</string>
<string name="user_add_user" msgid="7876449291500212468">"प्रयोगकर्ता कनेक्ट गर्नुहोस्"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथि कनेक्ट गर्नुहोस्"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"गेस्ट मोडबाट बाहिर निस्कियोस्"</string>
+ <string name="guest_exit_guest" msgid="5908239569510734136">"अथिति हटाउनुहोस्"</string>
<string name="guest_reset_guest" msgid="6110013010356013758">"अतिथि सत्र रिसेट गर्नुहोस्"</string>
<string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"अतिथिका रूपमा ब्राउज गर्ने सेसन रिसेट गर्ने हो?"</string>
<string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"यी अतिथि हटाउने हो?"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index d47a1f4..337b011 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"Escolher perfil"</string>
<string name="category_personal" msgid="6236798763159385225">"Pessoal"</string>
<string name="category_work" msgid="4014193632325996115">"Trabalho"</string>
- <string name="category_private" msgid="4244892185452788977">"Particular"</string>
+ <string name="category_private" msgid="4244892185452788977">"Privado"</string>
<string name="category_clone" msgid="1554511758987195974">"Clone"</string>
<string name="development_settings_title" msgid="140296922921597393">"Opções do desenvolvedor"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Ativar opções do desenvolvedor"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index d47a1f4..337b011 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -237,7 +237,7 @@
<string name="choose_profile" msgid="343803890897657450">"Escolher perfil"</string>
<string name="category_personal" msgid="6236798763159385225">"Pessoal"</string>
<string name="category_work" msgid="4014193632325996115">"Trabalho"</string>
- <string name="category_private" msgid="4244892185452788977">"Particular"</string>
+ <string name="category_private" msgid="4244892185452788977">"Privado"</string>
<string name="category_clone" msgid="1554511758987195974">"Clone"</string>
<string name="development_settings_title" msgid="140296922921597393">"Opções do desenvolvedor"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Ativar opções do desenvolvedor"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index ff62ba0..e8acd6e 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -161,7 +161,7 @@
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"ரத்துசெய்"</string>
<string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"இணைத்தலானது உங்கள் தொடர்புகள், அழைப்பு வரலாறுக்கான அணுகலை வழங்குகிறது."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைய முடியவில்லை."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"தவறான பின் அல்லது கடவுச்சொல் காரணமாக <xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"தவறான பின் அல்லது கடவுச்சாவி காரணமாக <xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> இணைப்பதை நிராகரித்தது."</string>
<string name="bluetooth_talkback_computer" msgid="3736623135703893773">"கணினி"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 6aea659..e8bac31 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -492,9 +492,9 @@
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
<string name="power_charging_limited" msgid="8202147604844938236">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj işlemi optimize edildi"</string>
<string name="power_charging_future_paused" msgid="1809543660923642799">"<xliff:g id="LEVEL">%1$s</xliff:g> ‑ Şarj ediliyor"</string>
- <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - <xliff:g id="TIME">%3$s</xliff:g> içinde tamamen dolacak"</string>
- <string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> içinde tamamen şarj olacak"</string>
- <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"<xliff:g id="TIME">%1$s</xliff:g> içinde tamamen şarj olacak"</string>
+ <string name="power_fast_charging_duration_v2" msgid="3797735998640359490">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATUS">%2$s</xliff:g> - Tamamen dolacağı zaman: <xliff:g id="TIME">%3$s</xliff:g>"</string>
+ <string name="power_charging_duration_v2" msgid="2938998284074003248">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olacağı zaman: <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="power_remaining_charging_duration_only_v2" msgid="5358176435722950193">"Tamamen şarj olacağı zaman: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_remaining_fast_charging_duration_only_v2" msgid="6270950195810579563">"<xliff:g id="TIME">%1$s</xliff:g> itibarıyla tamamen dolacak"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index ed964a9..b3e48b2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -209,44 +209,34 @@
CachedBluetoothDevice mainDevice = findMainDevice(cachedDevice);
if (mainDevice != null) {
if (mainDevice.isConnected()) {
- // When main device exists and in connected state, receiving sub device
- // connection. To refresh main device UI
+ // Sub/member device is connected and main device is connected
+ // To refresh main device UI
mainDevice.refresh();
} else {
- // When both Hearing Aid devices are disconnected, receiving sub device
- // connection. To switch content and dispatch to notify UI change
- mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
- mainDevice.switchSubDeviceContent();
- mainDevice.refresh();
- // It is necessary to do remove and add for updating the mapping on
- // preference and device
- mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+ // Sub/member device is connected and main device is disconnected
+ // To switch content and dispatch to notify UI change
+ switchDeviceContent(mainDevice, cachedDevice);
}
return true;
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
- mainDevice = findMainDevice(cachedDevice);
if (cachedDevice.getUnpairing()) {
return true;
}
+ mainDevice = findMainDevice(cachedDevice);
if (mainDevice != null) {
- // When main device exists, receiving sub device disconnection
+ // Sub/member device is disconnected and main device exists
// To update main device UI
mainDevice.refresh();
return true;
}
- CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
- if (subDevice != null && subDevice.isConnected()) {
- // Main device is disconnected and sub device is connected
- // To copy data from sub device to main device
- mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
- cachedDevice.switchSubDeviceContent();
- cachedDevice.refresh();
- // It is necessary to do remove and add for updating the mapping on
- // preference and device
- mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
-
+ CachedBluetoothDevice connectedSecondaryDevice = getConnectedSecondaryDevice(
+ cachedDevice);
+ if (connectedSecondaryDevice != null) {
+ // Main device is disconnected and sub/member device is connected
+ // To switch content and dispatch to notify UI change
+ switchDeviceContent(cachedDevice, connectedSecondaryDevice);
return true;
}
break;
@@ -254,6 +244,29 @@
return false;
}
+ private void switchDeviceContent(CachedBluetoothDevice mainDevice,
+ CachedBluetoothDevice secondaryDevice) {
+ mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
+ if (mainDevice.getSubDevice() != null
+ && mainDevice.getSubDevice().equals(secondaryDevice)) {
+ mainDevice.switchSubDeviceContent();
+ } else {
+ mainDevice.switchMemberDeviceContent(secondaryDevice);
+ }
+ mainDevice.refresh();
+ // It is necessary to do remove and add for updating the mapping on
+ // preference and device
+ mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+ }
+
+ private CachedBluetoothDevice getConnectedSecondaryDevice(CachedBluetoothDevice cachedDevice) {
+ if (cachedDevice.getSubDevice() != null && cachedDevice.getSubDevice().isConnected()) {
+ return cachedDevice.getSubDevice();
+ }
+ return cachedDevice.getMemberDevice().stream().filter(
+ CachedBluetoothDevice::isConnected).findAny().orElse(null);
+ }
+
void onActiveDeviceChanged(CachedBluetoothDevice device) {
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING)) {
if (device.isActiveDevice(BluetoothProfile.HEARING_AID) || device.isActiveDevice(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index 4188d2e..bf927a1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -681,6 +681,53 @@
verify(mCachedDevice1).refresh();
}
+
+ /**
+ * Test onProfileConnectionStateChangedIfProcessed.
+ * When main device is disconnected, to verify switch() result for member device connected
+ * event
+ */
+ @Test
+ public void onProfileConnectionStateChanged_connect_member_mainDisconnected_switch() {
+ when(mCachedDevice1.isConnected()).thenReturn(false);
+ when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
+ when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_1);
+ mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+ mCachedDevice1.addMemberDevice(mCachedDevice2);
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice1);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice2);
+ assertThat(mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(
+ mCachedDevice2, BluetoothProfile.STATE_CONNECTED)).isTrue();
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice2);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice1);
+ verify(mCachedDevice1).refresh();
+ }
+
+ /**
+ * Test onProfileConnectionStateChangedIfProcessed.
+ * When member device is connected, to verify switch() result for main device disconnected
+ * event
+ */
+ @Test
+ public void onProfileConnectionStateChanged_disconnect_main_subDeviceConnected_switch() {
+ when(mCachedDevice2.isConnected()).thenReturn(true);
+ when(mCachedDevice1.getGroupId()).thenReturn(GROUP_ID_1);
+ when(mCachedDevice2.getGroupId()).thenReturn(GROUP_ID_1);
+ mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+ mCachedDevice1.addMemberDevice(mCachedDevice2);
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice1);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice2);
+ assertThat(mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(
+ mCachedDevice1, BluetoothProfile.STATE_DISCONNECTED)).isTrue();
+
+ assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice2);
+ assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice1);
+ verify(mCachedDevice1).refresh();
+ }
+
@Test
public void onActiveDeviceChanged_connected_callSetStrategies() {
when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn(
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 5245456..00fb7a1 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -80,6 +80,7 @@
Settings.System.SIP_RECEIVE_CALLS,
Settings.System.POINTER_SPEED,
Settings.System.POINTER_FILL_STYLE,
+ Settings.System.POINTER_SCALE,
Settings.System.VIBRATE_ON,
Settings.System.VIBRATE_WHEN_RINGING,
Settings.System.RINGTONE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 2c3be4c..4235bc4 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -26,6 +26,8 @@
import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.URI_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.VIBRATION_INTENSITY_VALIDATOR;
+import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
+import static android.view.PointerIcon.LARGE_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BEGIN;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_END;
@@ -211,6 +213,8 @@
VALIDATORS.put(System.POINTER_FILL_STYLE,
new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_FILL_BEGIN,
POINTER_ICON_VECTOR_STYLE_FILL_END));
+ VALIDATORS.put(System.POINTER_SCALE,
+ new InclusiveFloatRangeValidator(DEFAULT_POINTER_SCALE, LARGE_POINTER_SCALE));
VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7));
VALIDATORS.put(System.TOUCHPAD_NATURAL_SCROLLING, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.TOUCHPAD_TAP_TO_CLICK, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 625b8e4..384cb7e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2915,6 +2915,9 @@
dumpSetting(s, p,
Settings.System.POINTER_FILL_STYLE,
SystemSettingsProto.Pointer.POINTER_FILL_STYLE);
+ dumpSetting(s, p,
+ Settings.System.POINTER_SCALE,
+ SystemSettingsProto.Pointer.POINTER_SCALE);
p.end(pointerToken);
dumpSetting(s, p,
Settings.System.POINTER_SPEED,
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 1e79bb7..58c39b4 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -368,6 +368,7 @@
"tests/src/**/systemui/shared/system/RemoteTransitionTest.java",
"tests/src/**/systemui/navigationbar/NavigationBarControllerImplTest.java",
"tests/src/**/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt",
+ "tests/src/**/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt",
"tests/src/**/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt",
"tests/src/**/systemui/notetask/LaunchNotesRoleSettingsTrampolineActivityTest.kt",
"tests/src/**/systemui/notetask/shortcut/LaunchNoteTaskActivityTest.kt",
@@ -784,7 +785,6 @@
kotlincflags: ["-Xjvm-default=all"],
optimize: {
shrink_resources: false,
- optimized_shrink_resources: false,
proguard_flags_files: ["proguard.flags"],
},
@@ -921,7 +921,6 @@
optimize: true,
shrink: true,
shrink_resources: true,
- optimized_shrink_resources: true,
ignore_warnings: false,
proguard_compatibility: false,
},
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bd6efe5..8a99263 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -387,7 +387,7 @@
android:killAfterRestore="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
- android:icon="@drawable/android14_patch_adaptive"
+ android:icon="@drawable/android15_patch_adaptive"
android:process="com.android.systemui"
android:supportsRtl="true"
android:theme="@style/Theme.SystemUI"
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml
index 160d310..f12278a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt-rBR/strings.xml
@@ -2,7 +2,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu de acessibilidade"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"\"Acessibilidade\" é um menu grande mostrado na tela para controlar seu dispositivo. Você pode bloquear o dispositivo, controlar o volume e o brilho, fazer capturas de tela e muito mais."</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Com este menu de tamanho grande na tela, você consegue bloquear o dispositivo, ajustar o volume e o brilho, fazer capturas de tela, entre outras funções de controle do aparelho."</string>
<string name="assistant_label" msgid="6796392082252272356">"Assistente"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Google Assistente"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Configurações de acessibilidade"</string>
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml
index 160d310..f12278a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml
+++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-pt/strings.xml
@@ -2,7 +2,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="accessibility_menu_service_name" msgid="730136711554740131">"Menu de acessibilidade"</string>
- <string name="accessibility_menu_intro" msgid="3164193281544042394">"\"Acessibilidade\" é um menu grande mostrado na tela para controlar seu dispositivo. Você pode bloquear o dispositivo, controlar o volume e o brilho, fazer capturas de tela e muito mais."</string>
+ <string name="accessibility_menu_intro" msgid="3164193281544042394">"Com este menu de tamanho grande na tela, você consegue bloquear o dispositivo, ajustar o volume e o brilho, fazer capturas de tela, entre outras funções de controle do aparelho."</string>
<string name="assistant_label" msgid="6796392082252272356">"Assistente"</string>
<string name="assistant_utterance" msgid="65509599221141377">"Google Assistente"</string>
<string name="a11y_settings_label" msgid="3977714687248445050">"Configurações de acessibilidade"</string>
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 85aa33a..c61f996 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1076,6 +1076,16 @@
}
flag {
+ name: "enable_efficient_display_repository"
+ namespace: "systemui"
+ description: "Decide whether to use the new implementation of DisplayRepository that minimizes binder calls and background lock contention."
+ bug: "345472038"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "notification_media_manager_background_execution"
namespace: "systemui"
description: "Decide whether to execute binder calls in background thread"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index a1f8f1b..b1258ba 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -68,6 +68,7 @@
val Grid = ElementKey("CommunalContent")
val LockIcon = ElementKey("CommunalLockIcon")
val IndicationArea = ElementKey("CommunalIndicationArea")
+ val StatusBar = ElementKey("StatusBar")
}
}
@@ -92,6 +93,7 @@
fade(Communal.Elements.Grid)
fade(Communal.Elements.IndicationArea)
fade(Communal.Elements.LockIcon)
+ fade(Communal.Elements.StatusBar)
}
timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) }
}
@@ -252,7 +254,10 @@
Box(
Modifier.matchParentSize()
.background(colors.primary)
- .animatedRadialGradientBackground(colors.primary, colors.primaryContainer)
+ .animatedRadialGradientBackground(
+ toColor = colors.primary,
+ fromColor = colors.primaryContainer.copy(alpha = 0.6f)
+ )
)
BackgroundTopScrim()
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
index 60b6f62..b353b5a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt
@@ -16,13 +16,16 @@
package com.android.systemui.communal.ui.compose
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection
import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines
@@ -38,19 +41,24 @@
private val interactionHandler: WidgetInteractionHandler,
private val dialogFactory: SystemUIDialogFactory,
private val lockSection: LockSection,
+ private val ambientStatusBarSection: AmbientStatusBarSection,
) {
-
@Composable
fun SceneScope.Content(modifier: Modifier = Modifier) {
Layout(
modifier = modifier.fillMaxSize(),
content = {
- CommunalHub(
- viewModel = viewModel,
- interactionHandler = interactionHandler,
- dialogFactory = dialogFactory,
- modifier = Modifier.element(Communal.Elements.Grid)
- )
+ Box(modifier = Modifier.fillMaxSize()) {
+ with(ambientStatusBarSection) {
+ AmbientStatusBar(modifier = Modifier.fillMaxWidth())
+ }
+ CommunalHub(
+ viewModel = viewModel,
+ interactionHandler = interactionHandler,
+ dialogFactory = dialogFactory,
+ modifier = Modifier.element(Communal.Elements.Grid)
+ )
+ }
with(lockSection) {
LockIcon(
overrideColor = LocalAndroidColorScheme.current.onPrimaryContainer,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index eccb072..f43064a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -26,7 +26,6 @@
import androidx.annotation.VisibleForTesting
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
-import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateFloatAsState
@@ -46,6 +45,7 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -585,24 +585,23 @@
)
.onSizeChanged { setToolbarSize(it) },
) {
- val spacerModifier = Modifier.width(ButtonDefaults.IconSpacing)
-
- if (!removeEnabled) {
- Button(
- modifier = Modifier.align(Alignment.CenterStart),
- onClick = onOpenWidgetPicker,
- colors = filledButtonColors(),
- contentPadding = Dimensions.ButtonPadding
- ) {
- Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
- Spacer(spacerModifier)
- Text(
- text = stringResource(R.string.hub_mode_add_widget_button_text),
- )
- }
+ ToolbarButton(
+ isPrimary = !removeEnabled,
+ modifier = Modifier.align(Alignment.CenterStart),
+ onClick = onOpenWidgetPicker,
+ ) {
+ Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
+ Text(
+ text = stringResource(R.string.hub_mode_add_widget_button_text),
+ )
}
- if (removeEnabled) {
+ AnimatedVisibility(
+ modifier = Modifier.align(Alignment.Center),
+ visible = removeEnabled,
+ enter = fadeIn(),
+ exit = fadeOut()
+ ) {
Button(
onClick = onRemoveClicked,
colors = filledButtonColors(),
@@ -610,33 +609,97 @@
modifier =
Modifier.graphicsLayer { alpha = removeButtonAlpha }
.onGloballyPositioned { setRemoveButtonCoordinates(it) }
- .align(Alignment.Center)
) {
- RemoveButtonContent(spacerModifier)
+ Row(
+ horizontalArrangement =
+ Arrangement.spacedBy(
+ ButtonDefaults.IconSpacing,
+ Alignment.CenterHorizontally
+ ),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(Icons.Default.Close, stringResource(R.string.button_to_remove_widget))
+ Text(
+ text = stringResource(R.string.button_to_remove_widget),
+ )
+ }
}
}
- if (!removeEnabled) {
- Button(
- modifier = Modifier.align(Alignment.CenterEnd),
- onClick = onEditDone,
- colors = filledButtonColors(),
- contentPadding = Dimensions.ButtonPadding
+ ToolbarButton(
+ isPrimary = !removeEnabled,
+ modifier = Modifier.align(Alignment.CenterEnd),
+ onClick = onEditDone,
+ ) {
+ Icon(
+ Icons.Default.Check,
+ stringResource(id = R.string.hub_mode_editing_exit_button_text)
+ )
+ Text(
+ text = stringResource(R.string.hub_mode_editing_exit_button_text),
+ )
+ }
+ }
+}
+
+/**
+ * Toolbar button that displays as a filled button if primary, and an outline button if secondary.
+ */
+@Composable
+private fun ToolbarButton(
+ isPrimary: Boolean = true,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ content: @Composable RowScope.() -> Unit
+) {
+ val colors = LocalAndroidColorScheme.current
+ AnimatedVisibility(
+ visible = isPrimary,
+ modifier = modifier,
+ enter = fadeIn(),
+ exit = fadeOut()
+ ) {
+ Button(
+ onClick = onClick,
+ colors = filledButtonColors(),
+ contentPadding = Dimensions.ButtonPadding,
+ ) {
+ Row(
+ horizontalArrangement =
+ Arrangement.spacedBy(ButtonDefaults.IconSpacing, Alignment.CenterHorizontally),
+ verticalAlignment = Alignment.CenterVertically
) {
- Icon(
- Icons.Default.Check,
- stringResource(id = R.string.hub_mode_editing_exit_button_text)
- )
- Spacer(spacerModifier)
- Text(
- text = stringResource(R.string.hub_mode_editing_exit_button_text),
- )
+ content()
+ }
+ }
+ }
+
+ AnimatedVisibility(
+ visible = !isPrimary,
+ modifier = modifier,
+ enter = fadeIn(),
+ exit = fadeOut()
+ ) {
+ OutlinedButton(
+ onClick = onClick,
+ colors =
+ ButtonDefaults.outlinedButtonColors(
+ contentColor = colors.primary,
+ ),
+ border = BorderStroke(width = 2.0.dp, color = colors.primary),
+ contentPadding = Dimensions.ButtonPadding,
+ ) {
+ Row(
+ horizontalArrangement =
+ Arrangement.spacedBy(ButtonDefaults.IconSpacing, Alignment.CenterHorizontally),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ content()
}
}
}
}
-@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun AnimatedVisibilityScope.ButtonToEditWidgets(
onClick: () -> Unit,
@@ -739,15 +802,6 @@
}
@Composable
-private fun RemoveButtonContent(spacerModifier: Modifier) {
- Icon(Icons.Default.Close, stringResource(R.string.button_to_remove_widget))
- Spacer(spacerModifier)
- Text(
- text = stringResource(R.string.button_to_remove_widget),
- )
-}
-
-@Composable
private fun filledButtonColors(): ButtonColors {
val colors = LocalAndroidColorScheme.current
return ButtonDefaults.buttonColors(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt
new file mode 100644
index 0000000..3b335fa
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/AmbientStatusBarSection.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.communal.ui.compose.section
+
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.viewinterop.AndroidView
+import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.ambient.statusbar.dagger.AmbientStatusBarComponent
+import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarView
+import com.android.systemui.communal.ui.compose.Communal
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+class AmbientStatusBarSection
+@Inject
+constructor(
+ private val factory: AmbientStatusBarComponent.Factory,
+) {
+ @Composable
+ fun SceneScope.AmbientStatusBar(modifier: Modifier = Modifier) {
+ AndroidView(
+ factory = { context ->
+ (LayoutInflater.from(context)
+ .inflate(
+ /* resource = */ R.layout.ambient_status_bar_view,
+ /* root = */ FrameLayout(context),
+ /* attachToRoot = */ false,
+ ) as AmbientStatusBarView)
+ .apply {
+ visibility = View.VISIBLE
+ factory.create(this).getController().apply { init() }
+ }
+ },
+ modifier = modifier.element(Communal.Elements.StatusBar)
+ )
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 10c4030..68395b4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -59,6 +59,13 @@
goneToShadeTransition(durationScale = 0.9)
}
from(Scenes.Gone, to = Scenes.QuickSettings) { goneToQuickSettingsTransition() }
+ from(
+ Scenes.Gone,
+ to = Scenes.QuickSettings,
+ key = SlightlyFasterShadeCollapse,
+ ) {
+ goneToQuickSettingsTransition(durationScale = 0.9)
+ }
from(Scenes.Gone, to = Scenes.QuickSettingsShade) { goneToQuickSettingsShadeTransition() }
from(Scenes.Lockscreen, to = Scenes.Bouncer) { lockscreenToBouncerTransition() }
from(Scenes.Lockscreen, to = Scenes.Communal) { lockscreenToCommunalTransition() }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index ac3e015..b5a10ca 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -19,7 +19,10 @@
import android.view.ContextThemeWrapper
import android.view.ViewGroup
+import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -32,7 +35,9 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
@@ -40,6 +45,7 @@
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
@@ -58,6 +64,7 @@
import com.android.compose.animation.scene.TransitionState
import com.android.compose.animation.scene.ValueKey
import com.android.compose.animation.scene.animateElementFloatAsState
+import com.android.compose.modifiers.thenIf
import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.settingslib.Utils
import com.android.systemui.battery.BatteryMeterView
@@ -69,6 +76,7 @@
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.onScrimDim
import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight
import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
@@ -79,7 +87,6 @@
import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
import com.android.systemui.statusbar.policy.Clock
-import kotlin.math.max
object ShadeHeader {
object Elements {
@@ -103,6 +110,8 @@
object Colors {
val ColorScheme.shadeHeaderText: Color
get() = Color.White
+ val ColorScheme.onScrimDim: Color
+ get() = Color.DarkGray
}
object TestTags {
@@ -130,7 +139,7 @@
val horizontalPadding =
max(LocalScreenCornerRadius.current / 2f, Shade.Dimensions.HorizontalPadding)
- val useExpandedFormat by
+ val useExpandedTextFormat by
remember(cutoutLocation) {
derivedStateOf {
cutoutLocation != CutoutLocation.CENTER ||
@@ -138,6 +147,10 @@
}
}
+ val isLargeScreenLayout =
+ LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Medium ||
+ LocalWindowSizeClass.current.widthSizeClass == WindowWidthSizeClass.Expanded
+
val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle()
// This layout assumes it is globally positioned at (0, 0) and is the
@@ -182,22 +195,22 @@
Modifier.element(ShadeHeader.Elements.CollapsedContentEnd)
.padding(horizontal = horizontalPadding)
) {
+ if (isLargeScreenLayout) {
+ ShadeCarrierGroup(
+ viewModel = viewModel,
+ modifier = Modifier.align(Alignment.CenterVertically),
+ )
+ }
SystemIconContainer(
+ viewModel = viewModel,
+ isClickable = isLargeScreenLayout,
modifier = Modifier.align(Alignment.CenterVertically)
) {
- when (LocalWindowSizeClass.current.widthSizeClass) {
- WindowWidthSizeClass.Medium,
- WindowWidthSizeClass.Expanded ->
- ShadeCarrierGroup(
- viewModel = viewModel,
- modifier = Modifier.align(Alignment.CenterVertically),
- )
- }
StatusIcons(
viewModel = viewModel,
createTintedIconManager = createTintedIconManager,
statusBarIconController = statusBarIconController,
- useExpandedFormat = useExpandedFormat,
+ useExpandedFormat = useExpandedTextFormat,
modifier =
Modifier.align(Alignment.CenterVertically)
.padding(end = 6.dp)
@@ -206,7 +219,7 @@
BatteryIcon(
createBatteryMeterViewController =
createBatteryMeterViewController,
- useExpandedFormat = useExpandedFormat,
+ useExpandedFormat = useExpandedTextFormat,
modifier = Modifier.align(Alignment.CenterVertically),
)
}
@@ -322,7 +335,7 @@
modifier = Modifier.widthIn(max = 90.dp).align(Alignment.CenterVertically),
)
Spacer(modifier = Modifier.weight(1f))
- SystemIconContainer {
+ SystemIconContainer(viewModel = viewModel, isClickable = false) {
StatusIcons(
viewModel = viewModel,
createTintedIconManager = createTintedIconManager,
@@ -531,12 +544,30 @@
@Composable
private fun SystemIconContainer(
+ viewModel: ShadeHeaderViewModel,
+ isClickable: Boolean,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit
) {
- // TODO(b/298524053): add hover state for this container
+ val interactionSource = remember { MutableInteractionSource() }
+ val isHovered by interactionSource.collectIsHoveredAsState()
+
+ val hoverModifier = Modifier
+ .clip(RoundedCornerShape(CollapsedHeight / 4))
+ .background(MaterialTheme.colorScheme.onScrimDim)
+
Row(
- modifier = modifier.height(CollapsedHeight),
+ modifier = modifier
+ .height(CollapsedHeight)
+ .padding(vertical = CollapsedHeight / 4)
+ .thenIf(isClickable) {
+ Modifier.clickable(
+ interactionSource = interactionSource,
+ indication = null,
+ onClick = { viewModel.onSystemIconContainerClicked() },
+ )
+ }
+ .thenIf(isHovered) { hoverModifier },
content = content,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
index e1ae80f..6d03118 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt
@@ -88,7 +88,7 @@
} else {
MaterialTheme.colorScheme.surface
},
- shape = RoundedCornerShape(28.dp),
+ shape = RoundedCornerShape(20.dp),
contentColor =
if (viewModel.isActive) {
MaterialTheme.colorScheme.onTertiaryContainer
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
index 1b821d3..bb2daec 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt
@@ -91,7 +91,7 @@
contentDescription = label
},
onClick = { onCheckedChange(!viewModel.isActive) },
- shape = RoundedCornerShape(28.dp),
+ shape = RoundedCornerShape(20.dp),
colors = colors,
contentPadding = PaddingValues(0.dp)
) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index 7fd3a176..114dcf4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -381,18 +381,17 @@
// relayout/redraw for nothing.
fromValue
} else {
- // In the case of bouncing, if the value remains constant during the overscroll, we
- // should use the value of the scene we are bouncing around.
- if (!canOverflow && transition is TransitionState.HasOverscrollProperties) {
- val bouncingScene = transition.bouncingScene
- if (bouncingScene != null) {
- return sharedValue[bouncingScene]
- }
- }
-
+ val overscrollSpec = transition.currentOverscrollSpec
val progress =
- if (canOverflow) transition.progress
- else transition.progress.fastCoerceIn(0f, 1f)
+ when {
+ overscrollSpec == null -> {
+ if (canOverflow) transition.progress
+ else transition.progress.fastCoerceIn(0f, 1f)
+ }
+ overscrollSpec.scene == transition.toScene -> 1f
+ else -> 0f
+ }
+
sharedValue.type.lerp(fromValue, toValue, progress)
}
} else fromValue ?: toValue
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 980982a..5611c6e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -39,6 +39,8 @@
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.TraversableNode
+import androidx.compose.ui.node.traverseDescendants
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
@@ -165,7 +167,7 @@
private var currentTransitions: List<TransitionState.Transition>,
private var scene: Scene,
private var key: ElementKey,
-) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode {
+) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode, TraversableNode {
private var _element: Element? = null
private val element: Element
get() = _element!!
@@ -174,6 +176,8 @@
private val sceneState: Element.SceneState
get() = _sceneState!!
+ override val traverseKey: Any = ElementTraverseKey
+
override fun onAttach() {
super.onAttach()
updateElementAndSceneValues()
@@ -289,18 +293,15 @@
val isOtherSceneOverscrolling = overscrollScene != null && overscrollScene != scene.key
val isNotPartOfAnyOngoingTransitions = transitions.isNotEmpty() && transition == null
if (isNotPartOfAnyOngoingTransitions || isOtherSceneOverscrolling) {
- sceneState.lastOffset = Offset.Unspecified
- sceneState.lastScale = Scale.Unspecified
- sceneState.lastAlpha = Element.AlphaUnspecified
+ recursivelyClearPlacementValues()
+ sceneState.lastSize = Element.SizeUnspecified
val placeable = measurable.measure(constraints)
- sceneState.lastSize = placeable.size()
-
return layout(placeable.width, placeable.height) { /* Do not place */ }
}
val placeable =
- measure(layoutImpl, scene, element, transition, sceneState, measurable, constraints)
+ measure(layoutImpl, element, transition, sceneState, measurable, constraints)
sceneState.lastSize = placeable.size()
return layout(placeable.width, placeable.height) { place(transition, placeable) }
}
@@ -315,13 +316,10 @@
// scene when idle.
val coords =
coordinates ?: error("Element ${element.key} does not have any coordinates")
- val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords)
// No need to place the element in this scene if we don't want to draw it anyways.
if (!shouldPlaceElement(layoutImpl, scene.key, element, transition)) {
- sceneState.lastOffset = Offset.Unspecified
- sceneState.lastScale = Scale.Unspecified
- sceneState.lastAlpha = Element.AlphaUnspecified
+ recursivelyClearPlacementValues()
return
}
@@ -329,12 +327,11 @@
val targetOffset =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { it.targetOffset },
transformation = { it.offset },
- idleValue = targetOffsetInScene,
currentValue = { currentOffset },
isSpecified = { it != Offset.Unspecified },
::lerp,
@@ -395,18 +392,37 @@
return@placeWithLayer
}
- alpha = elementAlpha(layoutImpl, scene, element, transition, sceneState)
+ alpha = elementAlpha(layoutImpl, element, transition, sceneState)
compositingStrategy = CompositingStrategy.ModulateAlpha
}
}
}
}
+ /**
+ * Recursively clear the last placement values on this node and all descendants ElementNodes.
+ * This should be called when this node is not placed anymore, so that we correctly clear values
+ * for the descendants for which approachMeasure() won't be called.
+ */
+ private fun recursivelyClearPlacementValues() {
+ fun Element.SceneState.clearLastPlacementValues() {
+ lastOffset = Offset.Unspecified
+ lastScale = Scale.Unspecified
+ lastAlpha = Element.AlphaUnspecified
+ }
+
+ sceneState.clearLastPlacementValues()
+ traverseDescendants(ElementTraverseKey) { node ->
+ (node as ElementNode).sceneState.clearLastPlacementValues()
+ TraversableNode.Companion.TraverseDescendantsAction.ContinueTraversal
+ }
+ }
+
override fun ContentDrawScope.draw() {
element.wasDrawnInAnyScene = true
val transition = elementTransition(layoutImpl, element, currentTransitions)
- val drawScale = getDrawScale(layoutImpl, scene, element, transition, sceneState)
+ val drawScale = getDrawScale(layoutImpl, element, transition, sceneState)
if (drawScale == Scale.Default) {
drawContent()
} else {
@@ -421,6 +437,8 @@
}
companion object {
+ private val ElementTraverseKey = Any()
+
private fun maybePruneMaps(
layoutImpl: SceneTransitionLayoutImpl,
element: Element,
@@ -494,22 +512,23 @@
// Remove the interruption values to all scenes but the scene(s) where the element will be
// placed, to make sure that interruption deltas are computed only right after this interruption
// is prepared.
- fun maybeCleanPlacementValuesBeforeInterruption(sceneState: Element.SceneState) {
+ fun cleanInterruptionValues(sceneState: Element.SceneState) {
+ sceneState.sizeInterruptionDelta = IntSize.Zero
+ sceneState.offsetInterruptionDelta = Offset.Zero
+ sceneState.alphaInterruptionDelta = 0f
+ sceneState.scaleInterruptionDelta = Scale.Zero
+
if (!shouldPlaceElement(layoutImpl, sceneState.scene, element, transition)) {
sceneState.offsetBeforeInterruption = Offset.Unspecified
sceneState.alphaBeforeInterruption = Element.AlphaUnspecified
sceneState.scaleBeforeInterruption = Scale.Unspecified
-
- sceneState.offsetInterruptionDelta = Offset.Zero
- sceneState.alphaInterruptionDelta = 0f
- sceneState.scaleInterruptionDelta = Scale.Zero
}
}
- previousFromState?.let { maybeCleanPlacementValuesBeforeInterruption(it) }
- previousToState?.let { maybeCleanPlacementValuesBeforeInterruption(it) }
- fromState?.let { maybeCleanPlacementValuesBeforeInterruption(it) }
- toState?.let { maybeCleanPlacementValuesBeforeInterruption(it) }
+ previousFromState?.let { cleanInterruptionValues(it) }
+ previousToState?.let { cleanInterruptionValues(it) }
+ fromState?.let { cleanInterruptionValues(it) }
+ toState?.let { cleanInterruptionValues(it) }
}
/**
@@ -780,7 +799,6 @@
*/
private fun elementAlpha(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
element: Element,
transition: TransitionState.Transition?,
sceneState: Element.SceneState,
@@ -788,12 +806,11 @@
val alpha =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { 1f },
transformation = { it.alpha },
- idleValue = 1f,
currentValue = { 1f },
isSpecified = { true },
::lerp,
@@ -841,9 +858,8 @@
)
}
-private fun ApproachMeasureScope.measure(
+private fun measure(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
element: Element,
transition: TransitionState.Transition?,
sceneState: Element.SceneState,
@@ -858,12 +874,11 @@
val targetSize =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { it.targetSize },
transformation = { it.size },
- idleValue = lookaheadSize,
currentValue = { measurable.measure(constraints).also { maybePlaceable = it }.size() },
isSpecified = { it != Element.SizeUnspecified },
::lerp,
@@ -909,7 +924,6 @@
private fun ContentDrawScope.getDrawScale(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
element: Element,
transition: TransitionState.Transition?,
sceneState: Element.SceneState,
@@ -917,12 +931,11 @@
val scale =
computeValue(
layoutImpl,
- scene,
+ sceneState,
element,
transition,
sceneValue = { Scale.Default },
transformation = { it.drawScale },
- idleValue = Scale.Default,
currentValue = { Scale.Default },
isSpecified = { true },
::lerp,
@@ -989,11 +1002,12 @@
* Measurable.
*
* @param layoutImpl the [SceneTransitionLayoutImpl] associated to [element].
- * @param scene the scene containing [element].
+ * @param currentSceneState the scene state of the scene for which we are computing the value. Note
+ * that during interruptions, this could be the state of a scene that is neither
+ * [transition.toScene] nor [transition.fromScene].
* @param element the element being animated.
* @param sceneValue the value being animated.
* @param transformation the transformation associated to the value being animated.
- * @param idleValue the value when idle, i.e. when there is no transition happening.
* @param currentValue the value that would be used if it is not transformed. Note that this is
* different than [idleValue] even if the value is not transformed directly because it could be
* impacted by the transformations on other elements, like a parent that is being translated or
@@ -1003,12 +1017,11 @@
*/
private inline fun <T> computeValue(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ currentSceneState: Element.SceneState,
element: Element,
transition: TransitionState.Transition?,
sceneValue: (Element.SceneState) -> T,
transformation: (ElementTransformations) -> PropertyTransformation<T>?,
- idleValue: T,
currentValue: () -> T,
isSpecified: (T) -> Boolean,
lerp: (T, T, Float) -> T,
@@ -1030,19 +1043,22 @@
if (fromState == null && toState == null) {
// TODO(b/311600838): Throw an exception instead once layers of disposed elements are not
// run anymore.
- return idleValue
+ return sceneValue(currentSceneState)
}
+ val currentScene = currentSceneState.scene
if (transition is TransitionState.HasOverscrollProperties) {
val overscroll = transition.currentOverscrollSpec
- if (overscroll?.scene == scene.key) {
- val elementSpec = overscroll.transformationSpec.transformations(element.key, scene.key)
+ if (overscroll?.scene == currentScene) {
+ val elementSpec =
+ overscroll.transformationSpec.transformations(element.key, currentScene)
val propertySpec = transformation(elementSpec) ?: return currentValue()
- val overscrollState = checkNotNull(if (scene.key == toScene) toState else fromState)
+ val overscrollState = checkNotNull(if (currentScene == toScene) toState else fromState)
+ val idleValue = sceneValue(overscrollState)
val targetValue =
propertySpec.transform(
layoutImpl,
- scene,
+ currentScene,
element,
overscrollState,
transition,
@@ -1086,24 +1102,30 @@
return if (start == end) start else lerp(start, end, transition.progress)
}
- val transformation =
- transformation(transition.transformationSpec.transformations(element.key, scene.key))
- // If there is no transformation explicitly associated to this element value, let's use
- // the value given by the system (like the current position and size given by the layout
- // pass).
- ?: return currentValue()
-
// Get the transformed value, i.e. the target value at the beginning (for entering elements) or
// end (for leaving elements) of the transition.
val sceneState =
checkNotNull(
when {
- isSharedElement && scene.key == fromScene -> fromState
+ isSharedElement && currentScene == fromScene -> fromState
isSharedElement -> toState
else -> fromState ?: toState
}
)
+ // The scene for which we compute the transformation. Note that this is not necessarily
+ // [currentScene] because [currentScene] could be a different scene than the transition
+ // fromScene or toScene during interruptions.
+ val scene = sceneState.scene
+
+ val transformation =
+ transformation(transition.transformationSpec.transformations(element.key, scene))
+ // If there is no transformation explicitly associated to this element value, let's use
+ // the value given by the system (like the current position and size given by the layout
+ // pass).
+ ?: return currentValue()
+
+ val idleValue = sceneValue(sceneState)
val targetValue =
transformation.transform(
layoutImpl,
@@ -1125,7 +1147,7 @@
val rangeProgress = transformation.range?.progress(progress) ?: progress
// Interpolate between the value at rest and the value before entering/after leaving.
- val isEntering = scene.key == toScene
+ val isEntering = scene == toScene
return if (isEntering) {
lerp(targetValue, idleValue, rangeProgress)
} else {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index f32720c..7ea8cbd 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -293,7 +293,15 @@
width = fromSize.width
height = fromSize.height
} else {
- val size = lerp(fromSize, toSize, transition.progress)
+ val overscrollSpec = transition.currentOverscrollSpec
+ val progress =
+ when {
+ overscrollSpec == null -> transition.progress
+ overscrollSpec.scene == transition.toScene -> 1f
+ else -> 0f
+ }
+
+ val size = lerp(fromSize, toSize, progress)
width = size.width.coerceAtLeast(0)
height = size.height.coerceAtLeast(0)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 6a178c8..a8df6f4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -768,7 +768,7 @@
/** A [MutableSceneTransitionLayoutState] that holds the value for the current scene. */
internal class MutableSceneTransitionLayoutStateImpl(
initialScene: SceneKey,
- override var transitions: SceneTransitions,
+ override var transitions: SceneTransitions = transitions {},
private val canChangeScene: (SceneKey) -> Boolean = { true },
stateLinks: List<StateLink> = emptyList(),
enableInterruptions: Boolean = DEFAULT_INTERRUPTIONS_ENABLED,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
index b54afae..73ee451 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt
@@ -20,7 +20,6 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -34,7 +33,7 @@
) : PropertyTransformation<IntSize> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
@@ -60,7 +59,7 @@
// This simple implementation assumes that the size of [element] is the same as the size of
// the [anchor] in [scene], so simply transform to the size of the anchor in the other
// scene.
- return if (scene.key == transition.fromScene) {
+ return if (scene == transition.fromScene) {
anchorSizeIn(transition.toScene)
} else {
anchorSizeIn(transition.fromScene)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
index 2bab4f8..70dca4c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt
@@ -21,7 +21,6 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -33,7 +32,7 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
@@ -61,7 +60,7 @@
anchorOffsetIn(transition.toScene) ?: throwException(transition.toScene)
val offset = anchorToOffset - anchorFromOffset
- return if (scene.key == transition.toScene) {
+ return if (scene == transition.toScene) {
Offset(
value.x - offset.x,
value.y - offset.y,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
index 6704a3b..98c2dd3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt
@@ -20,7 +20,7 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.Scale
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -37,7 +37,7 @@
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
index 191a8fb..aa8dc38 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt
@@ -20,7 +20,7 @@
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -32,13 +32,13 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
value: Offset
): Offset {
- val sceneSize = scene.targetSize
+ val sceneSize = layoutImpl.scene(scene).targetSize
val elementSize = sceneState.targetSize
if (elementSize == Element.SizeUnspecified) {
return value
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
index 41f626e..ada814e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt
@@ -18,7 +18,7 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -28,7 +28,7 @@
) : PropertyTransformation<Float> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
index f5207dc..dca8f85 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt
@@ -19,7 +19,7 @@
import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
import kotlin.math.roundToInt
@@ -35,7 +35,7 @@
) : PropertyTransformation<IntSize> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 603f7ba..7be9ce1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -21,7 +21,7 @@
import androidx.compose.ui.util.fastCoerceIn
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -61,7 +61,7 @@
// to these internal classes.
fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
index 849c9d7..f066511 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt
@@ -22,7 +22,7 @@
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.ElementMatcher
import com.android.compose.animation.scene.OverscrollScope
-import com.android.compose.animation.scene.Scene
+import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransitionState
@@ -33,7 +33,7 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
@@ -55,7 +55,7 @@
) : PropertyTransformation<Offset> {
override fun transform(
layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
+ scene: SceneKey,
element: Element,
sceneState: Element.SceneState,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
index 6e8b208..a7889e2 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt
@@ -18,10 +18,13 @@
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -443,4 +446,56 @@
assertThat(lastValues[bar]?.get(SceneC)).isWithin(0.001f).of(7f)
assertThat(lastValues[bar]?.get(SceneD)).isWithin(0.001f).of(7f)
}
+
+ @Test
+ fun animatedValueDoesNotOverscrollWhenOverscrollIsSpecified() {
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions { overscroll(SceneB, Orientation.Horizontal) }
+ )
+ }
+
+ val key = ValueKey("foo")
+ val lastValues = mutableMapOf<SceneKey, Float>()
+
+ @Composable
+ fun SceneScope.animateFloat(value: Float, key: ValueKey) {
+ val animatedValue = animateSceneFloatAsState(value, key)
+ LaunchedEffect(animatedValue) {
+ snapshotFlow { animatedValue.value }.collect { lastValues[sceneKey] = it }
+ }
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state) {
+ scene(SceneA) { animateFloat(0f, key) }
+ scene(SceneB) { animateFloat(100f, key) }
+ }
+ }
+
+ // Overscroll on A at -100%: value should be interpolated given that there is no overscroll
+ // defined for scene A.
+ var progress by mutableStateOf(-1f)
+ rule.runOnIdle {
+ state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress }))
+ }
+ rule.waitForIdle()
+ assertThat(lastValues[SceneA]).isWithin(0.001f).of(-100f)
+ assertThat(lastValues[SceneB]).isWithin(0.001f).of(-100f)
+
+ // Middle of the transition.
+ progress = 0.5f
+ rule.waitForIdle()
+ assertThat(lastValues[SceneA]).isWithin(0.001f).of(50f)
+ assertThat(lastValues[SceneB]).isWithin(0.001f).of(50f)
+
+ // Overscroll on B at 200%: value should not be interpolated given that there is an
+ // overscroll defined for scene B.
+ progress = 2f
+ rule.waitForIdle()
+ assertThat(lastValues[SceneA]).isWithin(0.001f).of(100f)
+ assertThat(lastValues[SceneB]).isWithin(0.001f).of(100f)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 41cacb4..a18da73 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -47,10 +47,12 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.layout.approachLayout
import androidx.compose.ui.platform.LocalViewConfiguration
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
+import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
@@ -1719,4 +1721,220 @@
rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsNotDisplayed()
rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(40.dp, 40.dp)
}
+
+ @Test
+ fun lastPlacementValuesAreClearedOnNestedElements() {
+ val state = rule.runOnIdle { MutableSceneTransitionLayoutStateImpl(SceneA) }
+
+ @Composable
+ fun SceneScope.NestedFooBar() {
+ Box(Modifier.element(TestElements.Foo)) {
+ Box(Modifier.element(TestElements.Bar).size(10.dp))
+ }
+ }
+
+ lateinit var layoutImpl: SceneTransitionLayoutImpl
+ rule.setContent {
+ SceneTransitionLayoutForTesting(state, onLayoutImpl = { layoutImpl = it }) {
+ scene(SceneA) { NestedFooBar() }
+ scene(SceneB) { NestedFooBar() }
+ }
+ }
+
+ // Idle on A: composed and placed only in B.
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertIsDisplayed()
+ rule.onNode(isElement(TestElements.Bar, SceneA)).assertIsDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertDoesNotExist()
+ rule.onNode(isElement(TestElements.Bar, SceneB)).assertDoesNotExist()
+
+ assertThat(layoutImpl.elements).containsKey(TestElements.Foo)
+ assertThat(layoutImpl.elements).containsKey(TestElements.Bar)
+ val foo = layoutImpl.elements.getValue(TestElements.Foo)
+ val bar = layoutImpl.elements.getValue(TestElements.Bar)
+
+ assertThat(foo.sceneStates).containsKey(SceneA)
+ assertThat(bar.sceneStates).containsKey(SceneA)
+ assertThat(foo.sceneStates).doesNotContainKey(SceneB)
+ assertThat(bar.sceneStates).doesNotContainKey(SceneB)
+
+ val fooInA = foo.sceneStates.getValue(SceneA)
+ val barInA = bar.sceneStates.getValue(SceneA)
+ assertThat(fooInA.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(fooInA.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(fooInA.lastScale).isNotEqualTo(Scale.Unspecified)
+
+ assertThat(barInA.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(barInA.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(barInA.lastScale).isNotEqualTo(Scale.Unspecified)
+
+ // A => B: composed in both and placed only in B.
+ rule.runOnUiThread { state.startTransition(transition(from = SceneA, to = SceneB)) }
+ rule.onNode(isElement(TestElements.Foo, SceneA)).assertExists().assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Bar, SceneA)).assertExists().assertIsNotDisplayed()
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertIsDisplayed()
+ rule.onNode(isElement(TestElements.Bar, SceneB)).assertIsDisplayed()
+
+ assertThat(foo.sceneStates).containsKey(SceneB)
+ assertThat(bar.sceneStates).containsKey(SceneB)
+
+ val fooInB = foo.sceneStates.getValue(SceneB)
+ val barInB = bar.sceneStates.getValue(SceneB)
+ assertThat(fooInA.lastOffset).isEqualTo(Offset.Unspecified)
+ assertThat(fooInA.lastAlpha).isEqualTo(Element.AlphaUnspecified)
+ assertThat(fooInA.lastScale).isEqualTo(Scale.Unspecified)
+ assertThat(fooInB.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(fooInB.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(fooInB.lastScale).isNotEqualTo(Scale.Unspecified)
+
+ assertThat(barInA.lastOffset).isEqualTo(Offset.Unspecified)
+ assertThat(barInA.lastAlpha).isEqualTo(Element.AlphaUnspecified)
+ assertThat(barInA.lastScale).isEqualTo(Scale.Unspecified)
+ assertThat(barInB.lastOffset).isNotEqualTo(Offset.Unspecified)
+ assertThat(barInB.lastAlpha).isNotEqualTo(Element.AlphaUnspecified)
+ assertThat(barInB.lastScale).isNotEqualTo(Scale.Unspecified)
+ }
+
+ @Test
+ fun currentTransitionSceneIsUsedToComputeElementValues() = runTest {
+ val state =
+ rule.runOnIdle {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions {
+ from(SceneB, to = SceneC) {
+ scaleSize(TestElements.Foo, width = 2f, height = 3f)
+ }
+ }
+ )
+ }
+
+ @Composable
+ fun SceneScope.Foo() {
+ Box(Modifier.testTag("fooParentIn${sceneKey.debugName}")) {
+ Box(Modifier.element(TestElements.Foo).size(20.dp))
+ }
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(200.dp)) {
+ scene(SceneA) { Foo() }
+ scene(SceneB) {}
+ scene(SceneC) { Foo() }
+ }
+ }
+
+ // We have 2 transitions:
+ // - A => B at 100%
+ // - B => C at 0%
+ // So Foo should have a size of (40dp, 60dp) in both A and C given that it is scaling its
+ // size in B => C.
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(from = SceneA, to = SceneB, progress = { 1f }, onFinish = neverFinish())
+ )
+ state.startTransition(transition(from = SceneB, to = SceneC, progress = { 0f }))
+ }
+
+ rule.onNode(hasTestTag("fooParentInSceneA")).assertSizeIsEqualTo(40.dp, 60.dp)
+ rule.onNode(hasTestTag("fooParentInSceneC")).assertSizeIsEqualTo(40.dp, 60.dp)
+ }
+
+ @Test
+ fun interruptionDeltasAreProperlyCleaned() = runTest {
+ val state = rule.runOnIdle { MutableSceneTransitionLayoutStateImpl(SceneA) }
+
+ @Composable
+ fun SceneScope.Foo(offset: Dp) {
+ Box(Modifier.fillMaxSize()) {
+ Box(Modifier.offset(offset, offset).element(TestElements.Foo).size(20.dp))
+ }
+ }
+
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.size(200.dp)) {
+ scene(SceneA) { Foo(offset = 0.dp) }
+ scene(SceneB) { Foo(offset = 20.dp) }
+ scene(SceneC) { Foo(offset = 40.dp) }
+ }
+ }
+
+ // Start A => B at 50%.
+ val aToB =
+ transition(from = SceneA, to = SceneB, progress = { 0.5f }, onFinish = neverFinish())
+ rule.runOnUiThread { state.startTransition(aToB) }
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(10.dp, 10.dp)
+
+ // Start B => C at 0%. This will compute an interruption delta of (-10dp, -10dp) so that the
+ // position of Foo is unchanged and converges to (20dp, 20dp).
+ var interruptionProgress by mutableStateOf(1f)
+ val bToC =
+ transition(
+ from = SceneB,
+ to = SceneC,
+ progress = { 0f },
+ interruptionProgress = { interruptionProgress },
+ onFinish = neverFinish(),
+ )
+ rule.runOnUiThread { state.startTransition(bToC) }
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(10.dp, 10.dp)
+
+ // Finish the interruption and leave the transition progress at 0f. We should be at the same
+ // state as in B.
+ interruptionProgress = 0f
+ rule.onNode(isElement(TestElements.Foo, SceneC)).assertPositionInRootIsEqualTo(20.dp, 20.dp)
+
+ // Finish both transitions but directly start a new one B => A with interruption progress
+ // 100%. We should be at (20dp, 20dp), unless the interruption deltas have not been
+ // correctly cleaned.
+ rule.runOnUiThread {
+ state.finishTransition(aToB, idleScene = SceneB)
+ state.finishTransition(bToC, idleScene = SceneB)
+ state.startTransition(
+ transition(
+ from = SceneB,
+ to = SceneA,
+ progress = { 0f },
+ interruptionProgress = { 1f },
+ )
+ )
+ }
+ rule.onNode(isElement(TestElements.Foo, SceneB)).assertPositionInRootIsEqualTo(20.dp, 20.dp)
+ }
+
+ @Test
+ fun lastSizeIsUnspecifiedWhenOverscrollingOtherScene() = runTest {
+ val state =
+ rule.runOnIdle {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions { overscroll(SceneA, Orientation.Horizontal) }
+ )
+ }
+
+ @Composable
+ fun SceneScope.Foo() {
+ Box(Modifier.element(TestElements.Foo).size(10.dp))
+ }
+
+ lateinit var layoutImpl: SceneTransitionLayoutImpl
+ rule.setContent {
+ SceneTransitionLayoutForTesting(state, onLayoutImpl = { layoutImpl = it }) {
+ scene(SceneA) { Foo() }
+ scene(SceneB) { Foo() }
+ }
+ }
+
+ // Overscroll A => B on A.
+ rule.runOnUiThread {
+ state.startTransition(
+ transition(from = SceneA, to = SceneB, progress = { -1f }, onFinish = neverFinish())
+ )
+ }
+ rule.waitForIdle()
+
+ assertThat(
+ layoutImpl.elements.getValue(TestElements.Foo).sceneStates.getValue(SceneB).lastSize
+ )
+ .isEqualTo(Element.SizeUnspecified)
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 08532bd..a8dd572 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -21,6 +21,7 @@
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
+import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
@@ -333,6 +334,42 @@
}
@Test
+ fun layoutSizeDoesNotOverscrollWhenOverscrollIsSpecified() {
+ val state =
+ rule.runOnUiThread {
+ MutableSceneTransitionLayoutStateImpl(
+ SceneA,
+ transitions { overscroll(SceneB, Orientation.Horizontal) }
+ )
+ }
+
+ val layoutTag = "layout"
+ rule.setContent {
+ SceneTransitionLayout(state, Modifier.testTag(layoutTag)) {
+ scene(SceneA) { Box(Modifier.size(50.dp)) }
+ scene(SceneB) { Box(Modifier.size(70.dp)) }
+ }
+ }
+
+ // Overscroll on A at -100%: size should be interpolated given that there is no overscroll
+ // defined for scene A.
+ var progress by mutableStateOf(-1f)
+ rule.runOnIdle {
+ state.startTransition(transition(from = SceneA, to = SceneB, progress = { progress }))
+ }
+ rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(30.dp)
+
+ // Middle of the transition.
+ progress = 0.5f
+ rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(60.dp)
+
+ // Overscroll on B at 200%: size should not be interpolated given that there is an
+ // overscroll defined for scene B.
+ progress = 2f
+ rule.onNodeWithTag(layoutTag).assertSizeIsEqualTo(70.dp)
+ }
+
+ @Test
fun multipleTransitionsWillComposeMultipleScenes() {
val duration = 10 * 16L
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt
index e743c78..6d063a0 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestMatchers.kt
@@ -17,7 +17,7 @@
package com.android.compose.animation.scene
import androidx.compose.ui.test.SemanticsMatcher
-import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasAnyAncestor
import androidx.compose.ui.test.hasTestTag
/** A [SemanticsMatcher] that matches [element], optionally restricted to scene [scene]. */
@@ -25,6 +25,6 @@
return if (scene == null) {
hasTestTag(element.testTag)
} else {
- hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag))
+ hasTestTag(element.testTag) and hasAnyAncestor(hasTestTag(scene.testTag))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
index d84d151..201ed00 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewControllerTest.java
@@ -146,6 +146,7 @@
mDreamOverlayStateController,
mUserTracker,
mKosmos.getWifiInteractor(),
+ mKosmos.getCommunalSceneInteractor(),
mLogBuffer);
}
@@ -272,6 +273,7 @@
mDreamOverlayStateController,
mUserTracker,
mKosmos.getWifiInteractor(),
+ mKosmos.getCommunalSceneInteractor(),
mLogBuffer);
controller.onViewAttached();
verify(mView, never()).showIcon(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
index cfc6b33..a12b6f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorTest.kt
@@ -32,8 +32,11 @@
package com.android.systemui.keyguard.domain.interactor
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
@@ -76,6 +79,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun transitionToGone_keyguardOccluded_biometricAuthenticated() =
testScope.runTest {
transitionRepository.sendTransitionSteps(
@@ -96,6 +100,25 @@
}
@Test
+ @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
+ fun transitionToGone_keyguardOccludedThenAltBouncer_authed_wmStateRefactor() =
+ testScope.runTest {
+ transitionRepository.sendTransitionSteps(
+ from = KeyguardState.OCCLUDED,
+ to = KeyguardState.ALTERNATE_BOUNCER,
+ testScope
+ )
+ reset(transitionRepository)
+
+ // Authentication results in calling startDismissKeyguardTransition.
+ kosmos.keyguardTransitionInteractor.startDismissKeyguardTransition()
+ runCurrent()
+
+ assertThat(transitionRepository)
+ .startedTransition(from = KeyguardState.ALTERNATE_BOUNCER, to = KeyguardState.GONE)
+ }
+
+ @Test
fun noTransition_keyguardNotOccluded_biometricAuthenticated() =
testScope.runTest {
transitionRepository.sendTransitionSteps(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
index 6c5001a..6eb9862 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
@@ -53,6 +53,7 @@
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import junit.framework.Assert.assertEquals
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -299,6 +300,7 @@
fun testTransitionToOccluded_onWake() =
testScope.runTest {
kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
+ kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop(true)
powerInteractor.setAwakeForTest()
advanceTimeBy(100) // account for debouncing
@@ -312,6 +314,7 @@
testScope.runTest {
kosmos.fakeKeyguardRepository.setKeyguardShowing(false)
kosmos.fakeKeyguardRepository.setKeyguardDismissible(true)
+ kosmos.keyguardTransitionInteractor.startDismissKeyguardTransition()
powerInteractor.setAwakeForTest()
advanceTimeBy(100) // account for debouncing
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index addbdb6..7906a82 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.fakeCommandQueue
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -191,6 +192,7 @@
fun dismissAlpha() =
testScope.runTest {
val dismissAlpha by collectLastValue(underTest.dismissAlpha)
+ assertThat(dismissAlpha).isEqualTo(1f)
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
@@ -202,9 +204,9 @@
// User begins to swipe up
shadeRepository.setLegacyShadeExpansion(0.99f)
- // When not dismissable, no alpha value (null) should emit
+ // When not dismissable, the last alpha value should still be present
repository.setKeyguardDismissible(false)
- assertThat(dismissAlpha).isNull()
+ assertThat(dismissAlpha).isEqualTo(1f)
repository.setKeyguardDismissible(true)
shadeRepository.setLegacyShadeExpansion(0.98f)
@@ -212,9 +214,11 @@
}
@Test
- fun dismissAlpha_whenShadeIsExpandedEmitsNull() =
+ fun dismissAlpha_whenShadeResetsEmitsOne() =
testScope.runTest {
- val dismissAlpha by collectLastValue(underTest.dismissAlpha)
+ val dismissAlpha by collectValues(underTest.dismissAlpha)
+ assertThat(dismissAlpha[0]).isEqualTo(1f)
+ assertThat(dismissAlpha.size).isEqualTo(1)
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
@@ -222,14 +226,50 @@
testScope,
)
- repository.setStatusBarState(StatusBarState.SHADE_LOCKED)
- shadeRepository.setQsExpansion(1f)
+ // User begins to swipe up
+ repository.setStatusBarState(StatusBarState.KEYGUARD)
+ repository.setKeyguardDismissible(true)
+ shadeRepository.setLegacyShadeExpansion(0.98f)
- repository.setKeyguardDismissible(false)
- assertThat(dismissAlpha).isNull()
+ assertThat(dismissAlpha[1]).isGreaterThan(0.5f)
+ assertThat(dismissAlpha[1]).isLessThan(1f)
+ assertThat(dismissAlpha.size).isEqualTo(2)
+
+ // Now reset the shade
+ shadeRepository.setLegacyShadeExpansion(1f)
+ assertThat(dismissAlpha[2]).isEqualTo(1f)
+ assertThat(dismissAlpha.size).isEqualTo(3)
+ }
+
+ @Test
+ fun dismissAlpha_doesNotEmitWhileTransitioning() =
+ testScope.runTest {
+ val dismissAlpha by collectLastValue(underTest.dismissAlpha)
+ assertThat(dismissAlpha).isEqualTo(1f)
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.GONE,
+ value = 0f,
+ transitionState = TransitionState.STARTED,
+ ),
+ TransitionStep(
+ from = KeyguardState.AOD,
+ to = KeyguardState.GONE,
+ value = 0.1f,
+ transitionState = TransitionState.RUNNING,
+ ),
+ ),
+ testScope,
+ )
repository.setKeyguardDismissible(true)
- assertThat(dismissAlpha).isNull()
+ shadeRepository.setLegacyShadeExpansion(0.98f)
+
+ // Should still be one
+ assertThat(dismissAlpha).isEqualTo(1f)
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
index 9dc930b..6e16705 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt
@@ -197,7 +197,7 @@
@Test
@EnableSceneContainer
- fun surfaceBehindVisibility_fromLockscreenToGone_trueThroughout() =
+ fun surfaceBehindVisibility_fromLockscreenToGone_noUserInput_trueThroughout() =
testScope.runTest {
val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility)
val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
@@ -249,6 +249,43 @@
@Test
@EnableSceneContainer
+ fun surfaceBehindVisibility_fromLockscreenToGone_withUserInput_falseUntilInputStops() =
+ testScope.runTest {
+ val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility)
+ val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
+
+ // Before the transition, we start on Lockscreen so the surface should start invisible.
+ kosmos.setSceneTransition(ObservableTransitionState.Idle(Scenes.Lockscreen))
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ assertThat(isSurfaceBehindVisible).isFalse()
+
+ // Unlocked with fingerprint.
+ kosmos.deviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+
+ // Start the transition to Gone, the surface should not be visible while
+ // isUserInputOngoing is true
+ val isUserInputOngoing = MutableStateFlow(true)
+ kosmos.setSceneTransition(
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Gone,
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = isUserInputOngoing,
+ progress = flowOf(0.51f),
+ currentScene = flowOf(Scenes.Gone),
+ )
+ )
+ assertThat(isSurfaceBehindVisible).isFalse()
+
+ // When isUserInputOngoing becomes false, then the surface should become visible.
+ isUserInputOngoing.value = false
+ assertThat(isSurfaceBehindVisible).isTrue()
+ }
+
+ @Test
+ @EnableSceneContainer
fun surfaceBehindVisibility_fromBouncerToGone_becomesTrue() =
testScope.runTest {
val isSurfaceBehindVisible by collectLastValue(underTest.value.surfaceBehindVisibility)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
index 73e6506..bc0512a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt
@@ -152,7 +152,6 @@
underTest.setRecommendation(mediaRecommendation.copy(isActive = false))
assertThat(smartspaceMediaData).isNotEqualTo(mediaRecommendation)
- assertThat(smartspaceMediaData?.isActive).isFalse()
assertThat(underTest.isRecommendationActive()).isFalse()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
index e87c8ad..899122d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
@@ -35,6 +35,7 @@
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.ScreenRecordRepositoryImpl
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
@@ -72,11 +73,18 @@
.thenReturn(dialog)
}
+ private val screenRecordRepository =
+ ScreenRecordRepositoryImpl(
+ bgCoroutineContext = testScope.testScheduler,
+ recordingController = recordingController,
+ )
+
private val underTest =
ScreenRecordTileUserActionInteractor(
context,
testScope.testScheduler,
testScope.testScheduler,
+ screenRecordRepository,
recordingController,
keyguardInteractor,
keyguardDismissUtil,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index ac66e66..e40c8ee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-@file:OptIn(ExperimentalCoroutinesApi::class, ExperimentalCoroutinesApi::class)
+@file:OptIn(ExperimentalCoroutinesApi::class)
package com.android.systemui.scene.domain.startable
@@ -395,6 +395,7 @@
)
assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
underTest.start()
+ runCurrent()
kosmos.fakePowerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
@@ -1285,6 +1286,42 @@
}
@Test
+ fun switchToGone_whenSurfaceBehindLockscreenVisibleMidTransition() =
+ testScope.runTest {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ val transitionStateFlow =
+ prepareState(
+ authenticationMethod = AuthenticationMethodModel.None,
+ )
+ underTest.start()
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ // Swipe to Gone, more than halfway
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Gone,
+ currentScene = flowOf(Scenes.Gone),
+ progress = flowOf(0.51f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(true),
+ )
+ runCurrent()
+ // Lift finger
+ transitionStateFlow.value =
+ ObservableTransitionState.Transition(
+ fromScene = Scenes.Lockscreen,
+ toScene = Scenes.Gone,
+ currentScene = flowOf(Scenes.Gone),
+ progress = flowOf(0.51f),
+ isInitiatedByUserInput = true,
+ isUserInputOngoing = flowOf(false),
+ )
+ runCurrent()
+
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
fun switchToGone_extendUnlock() =
testScope.runTest {
val currentScene by collectLastValue(sceneInteractor.currentScene)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index f89f18a..3ded8a3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -6,15 +6,27 @@
import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.plugins.activityStarter
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.argThat
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -24,12 +36,16 @@
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
+@EnableSceneContainer
class ShadeHeaderViewModelTest : SysuiTestCase() {
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
private val mobileIconsInteractor = kosmos.fakeMobileIconsInteractor
+ private val sceneInteractor = kosmos.sceneInteractor
+ private val deviceEntryInteractor = kosmos.deviceEntryInteractor
private val underTest: ShadeHeaderViewModel = kosmos.shadeHeaderViewModel
@@ -77,6 +93,30 @@
)
}
+ @Test
+ fun onSystemIconContainerClicked_locked_collapsesShadeToLockscreen() =
+ testScope.runTest {
+ setDeviceEntered(false)
+ setScene(Scenes.Shade)
+
+ underTest.onSystemIconContainerClicked()
+ runCurrent()
+
+ assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun onSystemIconContainerClicked_unlocked_collapsesShadeToGone() =
+ testScope.runTest {
+ setDeviceEntered(true)
+ setScene(Scenes.Shade)
+
+ underTest.onSystemIconContainerClicked()
+ runCurrent()
+
+ assertThat(sceneInteractor.currentScene.value).isEqualTo(Scenes.Gone)
+ }
+
companion object {
private val SUB_1 =
SubscriptionModel(
@@ -93,6 +133,32 @@
profileClass = PROFILE_CLASS_UNSET,
)
}
+
+ private fun setScene(key: SceneKey) {
+ sceneInteractor.changeScene(key, "test")
+ sceneInteractor.setTransitionState(
+ MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key))
+ )
+ testScope.runCurrent()
+ }
+
+ private fun TestScope.setDeviceEntered(isEntered: Boolean) {
+ if (isEntered) {
+ // Unlock the device marking the device has entered.
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ runCurrent()
+ }
+ setScene(
+ if (isEntered) {
+ Scenes.Gone
+ } else {
+ Scenes.Lockscreen
+ }
+ )
+ assertThat(deviceEntryInteractor.isDeviceEntered.value).isEqualTo(isEntered)
+ }
}
private class IntentMatcherAction(private val action: String) : ArgumentMatcher<Intent> {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index c35c165..497484f90 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -42,6 +42,7 @@
import com.android.systemui.keyguard.shared.model.BurnInModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -842,6 +843,30 @@
}
@Test
+ @DisableSceneContainer
+ fun updateBounds_fromGone_withoutTransitions() =
+ testScope.runTest {
+ // Start step is already at 1.0
+ val runningStep = TransitionStep(GONE, AOD, 1.0f, TransitionState.RUNNING)
+ val finishStep = TransitionStep(GONE, AOD, 1.0f, TransitionState.FINISHED)
+
+ val bounds by collectLastValue(underTest.bounds)
+ val top = 123f
+ val bottom = 456f
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(runningStep)
+ runCurrent()
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(finishStep)
+ runCurrent()
+ keyguardRootViewModel.onNotificationContainerBoundsChanged(top, bottom)
+ runCurrent()
+
+ assertThat(bounds).isEqualTo(
+ NotificationContainerBounds(top = top, bottom = bottom)
+ )
+ }
+
+ @Test
fun alphaOnFullQsExpansion() =
testScope.runTest {
val viewState = ViewStateAccessor()
diff --git a/packages/SystemUI/res/drawable/android15_patch_adaptive.xml b/packages/SystemUI/res/drawable/android15_patch_adaptive.xml
new file mode 100644
index 0000000..d949200
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_adaptive.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/android15_patch_adaptive_background"/>
+ <foreground android:drawable="@drawable/android15_patch_adaptive_foreground"/>
+ <monochrome android:drawable="@drawable/android15_patch_monochrome"/>
+</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable/android15_patch_adaptive_background.xml b/packages/SystemUI/res/drawable/android15_patch_adaptive_background.xml
new file mode 100644
index 0000000..d4850d3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_adaptive_background.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <!-- space (themed version) -->
+ <path
+ android:pathData="M0,0h108v108h-108z"
+ android:fillColor="@android:color/system_neutral1_800"/>
+ <!-- stars (themed version) -->
+ <group>
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="@android:color/system_accent3_200"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="@android:color/system_accent3_200"/>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android15_patch_adaptive_foreground.xml b/packages/SystemUI/res/drawable/android15_patch_adaptive_foreground.xml
new file mode 100644
index 0000000..34f6ee0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_adaptive_foreground.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+
+ <!-- zoomies (themed version) -->
+ <group>
+ <path
+ android:pathData="M53,42C52.21,50.58 46.46,68.95 32.11,74.63C19.22,79.75 5.77,82.32 1.19,83.19C0.68,83.29 0.28,83.36 0,83.42V108H54H108V83.42C107.72,83.36 107.32,83.29 106.81,83.19C102.23,82.32 88.78,79.75 75.89,74.63C61.54,68.95 55.79,50.58 55,42H54H53Z"
+ android:fillColor="@android:color/system_accent1_100"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M53.25,42C52.88,50.53 50.44,69.01 43.68,74.67C36.91,80.33 32.65,82.86 31.37,83.41L54,102.87L76.63,83.41C75.35,82.86 71.09,80.33 64.32,74.67C57.56,69.01 55.12,50.53 54.75,42H54H53.25Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ <path
+ android:pathData="M54,42m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
+ android:fillColor="#ffffff"/>
+ </group>
+ <group>
+ <!-- head! it's like sputnik -->
+ <path
+ android:pathData="M54,94.25m-26.25,0a26.25,26.25 0,1 1,52.5 0a26.25,26.25 0,1 1,-52.5 0"
+ android:fillColor="#34A853"/>
+ <!-- ant -->
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#34A853"
+ android:strokeLineCap="round"/>
+ </group>
+ <!-- spaceship -->
+ <path
+ android:pathData="M54,34C52.34,34 51,35.29 51,36.88V40.44C51,40.75 51.25,41 51.56,41C51.87,41 52.13,40.75 52.13,40.44V39.48C52.13,38.87 52.63,38.37 53.25,38.37H54.75C55.37,38.37 55.87,38.87 55.87,39.48V40.44C55.87,40.75 56.13,41 56.44,41C56.75,41 57,40.75 57,40.44V36.88C57,35.29 55.66,34 54,34H54Z"
+ android:fillColor="#E9F3EB"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/android15_patch_monochrome.xml b/packages/SystemUI/res/drawable/android15_patch_monochrome.xml
new file mode 100644
index 0000000..a91cc86
--- /dev/null
+++ b/packages/SystemUI/res/drawable/android15_patch_monochrome.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <group>
+ <path
+ android:pathData="
+ M54,94.25
+ m-26.25,0
+ a26.25,26.25 0,1 1,52.5 0
+ a26.25,26.25 0,1 1,-52.5 0
+ "
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M38,63.5L44.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+ <path
+ android:pathData="M70,63.5L63.5,74.5"
+ android:strokeWidth="5"
+ android:fillColor="#00000000"
+ android:strokeColor="#000000"
+ android:strokeLineCap="round"/>
+
+ <path
+ android:pathData="
+ M54,34
+ C52.34,34 51,35.29 51,36.88
+ V40.44
+ C51,40.75 51.25,41 51.56,41
+ C51.87,41 52.13,40.75 52.13,40.44
+ V39.48
+ C52.13,38.87 52.63,38.37 53.25,38.37
+ H54.75
+ C55.37,38.37 55.87,38.87 55.87,39.48
+ V40.44
+ C55.87,40.75 56.13,41 56.44,41
+ C56.75,41 57,40.75 57,40.44
+ V36.88
+ C57,35.29 55.66,34 54,34
+ H54
+ Z
+ "
+ android:fillColor="#34A853"/>
+ <path
+ android:strokeWidth="1"
+ android:pathData="M54,40V67"
+ android:fillColor="#00000000"
+ android:strokeColor="#40FFFFFF"
+ />
+
+ <path
+ android:pathData="M32,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M33,61 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M71,34 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M62,56 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M68,47 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M72,55 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,36 h1v1h-1z"
+ android:fillColor="#ffffff"/>
+
+ <path
+ android:pathData="M72,49 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M46,53 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M32,45 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M43,37 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M78,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M34,51 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M76,41 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+ <path
+ android:pathData="M39,46 h2v2h-2z"
+ android:fillColor="#ffffff"/>
+
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 221b791..fbb07be 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -62,7 +62,9 @@
<com.android.systemui.keyguard.ui.view.KeyguardRootView
android:id="@id/keyguard_root_view"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ />
<!-- Shared container for the notification stack. Can be positioned by either
the keyguard_root_view or notification_panel -->
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index c25d8cb..a7dfdaa 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Skakel dit môre outomaties weer aan"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Kenmerke soos Kitsdeel en Kry My Toestel gebruik Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sal môreoggend aanskakel"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Oudiodeling"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deel tans oudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batterykrag"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Oudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kopstuk"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Watter deel van jou toestelervaring is geraak?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Kies soort kwessie"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skermopname"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Werkverrigting"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Gebruikerkoppelvlak"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termies"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Eenhandmodus"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Gehoortoestelle"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktief"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ontkoppel"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Gehoortoestelle"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bind nuwe toestel saam"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nuwe toestel saam te bind"</string>
@@ -1201,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-fi sal vir nou nie outomaties koppel nie"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Ontkoppel Ethernet om netwerke te wissel"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan programme en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporinginstellings verander. "<annotation id="link">"Verander"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Om toestelervaring te verbeter, kan apps en dienste steeds enige tyd na wi‑fi-netwerke soek, selfs wanneer wi‑fi af is. Jy kan dit in Wi-fi-opsporinginstellings verander. "<annotation id="link">"Verander"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Skakel vliegtuigmodus af"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> wil die volgende teël by Kitsinstellings voeg"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Voeg teël by"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gevou"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"oopgevou"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stilusbattery <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koppel jou stilus aan ’n laaier"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stilus se battery is amper pap"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Soekkortpaaie"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Vou ikoon in"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vou ikoon uit"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Sleutelbordlig"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Vlak %1$d van %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Huiskontroles"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ed6a3e1..396837e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ነገ እንደገና በራስ-ሰር አስጀምር"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"እንደ ፈጣን ማጋራት እና የእኔን መሣሪያ አግኝ ያሉ ባህሪዎች ብሉቱዝን ይጠቀማሉ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ብሉቱዝ ነገ ጠዋት ይበራል"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"የድምጽ ማጋራት"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ድምጽን በማጋራት ላይ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ባትሪ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ኦዲዮ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ማዳመጫ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"የትኛው የመሣሪያዎ ተሞክሮ ክፍል ተጎድቷል?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"የችግሩን አይነት ይምረጡ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"የማያ መቅረጫ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"አፈጻጸም"</string>
+ <string name="user_interface" msgid="3712869377953950887">"የተጠቃሚ በይነገፅ"</string>
+ <string name="thermal" msgid="6758074791325414831">"ተርማል"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"የአንድ እጅ ሁነታ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"የመስሚያ መሣሪያዎች"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ገቢር"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ግንኙነት ተቋርጧል"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"የመስማት ችሎታ መሣሪያ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"አዲስ መሣሪያ ያጣምሩ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"አዲስ መሣሪያ ለማጣመር ጠቅ ያድርጉ"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"የታጠፈ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"የተዘረጋ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"የብሮስፌ ባትሪ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ብሮስፌዎን ከኃይል መሙያ ጋር ያገናኙ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"የብሮስፌ ባትሪ ዝቅተኛ ነው"</string>
<string name="video_camera" msgid="7654002575156149298">"የቪድዮ ካሜራ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"የፍለጋ አቋራጮች"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"መዘርጊያ አዶ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ወይም"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"የቁልፍ ሰሌዳ የጀርባ ብርሃን"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"ደረጃ %1$d ከ %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"የቤት ውስጥ ቁጥጥሮች"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1502765..254549f 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"تفعيل البلوتوث تلقائيًا مرة أخرى غدًا"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"يُستخدَم البلوتوث في ميزات مثل Quick Share و\"العثور على جهازي\""</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"سيتم تفعيل البلوتوث صباح الغد"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"مشاركة الصوت"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"مشاركة الصوت"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"مستوى طاقة البطارية <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"صوت"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"سماعة الرأس"</string>
@@ -301,11 +303,11 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"المستخدم"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"الإنترنت"</string>
- <string name="quick_settings_networks_available" msgid="1875138606855420438">"الشبكات متوفرة"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"تتوفّر شبكات"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"الشبكات غير متوفرة"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"لا تتوفر أي شبكة Wi-Fi"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"جارٍ التفعيل…"</string>
- <string name="quick_settings_cast_title" msgid="3033553249449938182">"الإرسال"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"البث"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"جارٍ الإرسال"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"جهاز لا يحمل اسمًا"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"لا يتوفر أي جهاز"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"الأداء الحراري"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"وضع \"التصفح بيد واحدة\""</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعات الأذن الطبية"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"متّصلة حاليًا"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"غير متّصلة"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعات الأذن الطبية"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"إقران جهاز جديد"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"انقر لإقران جهاز جديد"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"اختصارات طلبات البحث"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"رمز التوسيع"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"أو"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"الإضاءة الخلفية للوحة المفاتيح"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"مستوى الإضاءة: %1$d من %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"إدارة المنزل آليًّا"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 00d673e..dd71023 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"কাইলৈ পুনৰ স্বয়ংক্ৰিয়ভাৱে অন কৰক"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share আৰু Find My Deviceৰ দৰে সুবিধাসমূহে ব্লুটুথ ব্যৱহাৰ কৰে"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"কাইলৈ পুৱা ব্লুটুথ অন হ’ব"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"অডিঅ’ শ্বেয়াৰ কৰা"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"অডিঅ’ শ্বেয়াৰ কৰি থকা হৈছে"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"বেটাৰী <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিঅ’"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডছেট"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"থাৰ্মেল"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"শুনাৰ ডিভাইচ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"সক্ৰিয় হৈ আছে"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"সংযোগ বিচ্ছিন্ন কৰা হ’ল"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"শুনাৰ ডিভাইচ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইচ পেয়াৰ কৰক"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইচ পেয়াৰ কৰিবলৈ ক্লিক কৰক"</string>
@@ -1265,8 +1265,8 @@
<string name="rear_display_bottom_sheet_confirm" msgid="1507591562761552899">"এতিয়াই স্ক্ৰীন সলনি কৰক"</string>
<string name="rear_display_folded_bottom_sheet_title" msgid="3930008746560711990">"ফ’নটো আনফ’ল্ড কৰক"</string>
<string name="rear_display_unfolded_bottom_sheet_title" msgid="6291111173057304055">"স্ক্ৰীন সলনি কৰিবনে?"</string>
- <string name="rear_display_folded_bottom_sheet_description" msgid="6842767125783222695">"অধিক ৰিজ’লিউছনৰ বাবে, পিছফালৰ কেমেৰাটো ব্যৱহাৰ কৰক"</string>
- <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"অধিক ৰিজ’লিউছনৰ বাবে, ফ’নটো লুটিয়াই দিয়ক"</string>
+ <string name="rear_display_folded_bottom_sheet_description" msgid="6842767125783222695">"অধিক ৰিজ’লিউশ্বনৰ বাবে, পিছফালৰ কেমেৰাটো ব্যৱহাৰ কৰক"</string>
+ <string name="rear_display_unfolded_bottom_sheet_description" msgid="7229961336309960201">"অধিক ৰিজ’লিউশ্বনৰ বাবে, ফ’নটো লুটিয়াই দিয়ক"</string>
<string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string>
<string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string>
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফ’ল্ড কৰা"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সন্ধানৰ শ্বৰ্টকাট"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"বিস্তাৰ কৰাৰ চিহ্ন"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীব’ৰ্ডৰ বেকলাইট"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dৰ %1$d স্তৰ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ঘৰৰ সা-সৰঞ্জামৰ নিয়ন্ত্ৰণ"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b3c0058..592bc06 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Sabah avtomatik aktiv edin"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Cəld Paylaşım və Cihazın Tapılması kimi funksiyalar Bluetooth istifadə edir"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sabah səhər aktiv ediləcək"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio paylaşma"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio paylaşılır"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batareya"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Qulaqlıq"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz istifadəsinə necə təsir etdi?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problem növü seçin"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran qeydəalma"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performans"</string>
+ <string name="user_interface" msgid="3712869377953950887">"İstifadəçi interfeysi"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Birəlli rejim"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eşitmə cihazları"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiv"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Bağlantı kəsildi"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eşitmə cihazları"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz birləşdirin"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz birləşdirmək üçün klikləyin"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"qatlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"açıq"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stilusun enerjisi: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Qələmi adapterə qoşun"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Qələm enerjisi azdır"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Axtarış qısayolları"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"İkonanı yığcamlaşdırın"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"İkonanı genişləndirin"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"və ya"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura işığı"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Səviyyə %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ev nizamlayıcıları"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 22afb40..9b27943 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatski ponovo uključi sutra"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcije kao što su Quick Share i Pronađi moj uređaj koriste Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth će se uključiti sutra ujutru"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Deljenje zvuka"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deli se zvuk"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Nivo baterije je <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termalna kamera"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednom rukom"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Veza je prekinuta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Upari novi uređaj"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili nov uređaj"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečice pretrage"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvetljenje tastature"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4fe7c5a..ca763cf 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Аўтаматычнае ўключэнне заўтра"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth выкарыстоўваецца такімі функцыямі і сэрвісамі, як Хуткае абагульванне і Знайсці прыладу"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth уключыцца заўтра раніцай"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Абагульванне аўдыя"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ідзе абагульванне аўдыя"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Узровень зараду: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Гук"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнітура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"З чым была звязана праблема, якая вам сустрэлася?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберыце тып праблемы"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запіс экрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Прадукцыйнасць"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Карыстальніцкі інтэрфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Тэрмальныя паказчыкі"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Рэжым кіравання адной рукой"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слыхавыя апараты"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Актыўныя"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Адключаны"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слыхавыя апараты"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спалучыць новую прыладу"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Націсніце, каб спалучыць новую прыладу"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складзена"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"раскладзена"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Зарад акумулятара пяра – <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Падключыце пяро да зараднай прылады"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Нізкі ўзровень зараду пяра"</string>
<string name="video_camera" msgid="7654002575156149298">"Відэакамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук спалучэнняў клавіш"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Разгарнуць\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Падсветка клавіятуры"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Узровень %1$d з %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Кіраванне домам"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 2cd65db..d50b116 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Автоматично включване отново утре"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Функции като „Бързо споделяне“ и „Намиране на устройството ми“ използват Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ще се включи утре сутрин"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Споделяне на звука"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Звукът се споделя"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалки"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С какво имахте проблем?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис на екрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ефективност"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Потребителски интерфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Термално"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим за работа с една ръка"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухови апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Няма връзка"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухови апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Сдвояване на ново устройство"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за сдвояване на ново устройство"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Батерия на писалката: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Свържете писалката към зарядно устройство"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Батерията на писалката е изтощена"</string>
<string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Търсете клавишни комбинации"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за свиване"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за разгъване"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка на клавиатурата"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d от %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за дома"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f8e350a..bb41b1b 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"আগামীকাল আবার অটোমেটিক চালু হবে"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"দ্রুত শেয়ার ও Find My Device-এর মতো ফিচার ব্লুটুথ ব্যবহার করে"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ব্লুটুথ আগামীকাল সকালে চালু হয়ে যাবে"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"অডিও শেয়ারিং"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"অডিও শেয়ার করা হচ্ছে"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"চার্জ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"অডিও"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"হেডসেট"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ডিভাইস ব্যবহার করার সময় কোথায় অসুবিধা হয়েছিল?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"সমস্যার প্রকার বেছে নিন"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"স্ক্রিন রেকর্ড"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"পারফর্ম্যান্স"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ইউজার ইন্টারফেস"</string>
+ <string name="thermal" msgid="6758074791325414831">"থার্মাল"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"এক হাতে ব্যবহার করার মোড"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"হিয়ারিং ডিভাইস"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"অ্যাক্টিভ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ডিসকানেক্ট হয়ে গেছে"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"হিয়ারিং ডিভাইস"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"নতুন ডিভাইস পেয়ার করুন"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"নতুন ডিভাইস পেয়ার করতে ক্লিক করুন"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফোল্ড করা রয়েছে"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ফোল্ড করা নেই"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"স্টাইলাস ব্যাটারি <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"কোনও চার্জারের সাথে আপনার স্টাইলাস কানেক্ট করুন"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"স্টাইলাস ব্যাটারিতে চার্জ কম আছে"</string>
<string name="video_camera" msgid="7654002575156149298">"ভিডিও ক্যামেরা"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সার্চ শর্টকাট"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"আইকন আড়াল করুন"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"আইকন বড় করুন"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"অথবা"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীবোর্ড ব্যাকলাইট"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-এর মধ্যে %1$d লেভেল"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"হোম কন্ট্রোল"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 60c936e..4916d80 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatski uključi ponovo sutra"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcije kao što su Quick Share i Pronađi moj uređaj koriste Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth će se uključiti sutra ujutro"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Dijeljenje zvuka"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Dijeljenje zvuka"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> baterije"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Koji dio uređaja je imao problem?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje ekrana"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performanse"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Korisnički interfejs"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termalno"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni aparati"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Veza je prekinuta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni aparati"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da uparite novi uređaj"</string>
@@ -1201,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"WiFi se trenutno ne može automatski povezati"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Da promijenite mrežu, isključite ethernet"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi poboljšanja iskustva s uređajem aplikacije i usluge i dalje mogu tražiti WiFi mreže bilo kada, čak i kada je WiFi isključen. Ovo možete promijeniti u Postavkama traženja WiFi mreže. "<annotation id="link">"Promijeni"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Radi poboljšanja iskustva s uređajem aplikacije i usluge i dalje mogu tražiti WiFi mreže bilo kada, čak i kada je WiFi isključen. Ovo možete promijeniti u postavkama traženja WiFi-ja. "<annotation id="link">"Promijeni"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"Isključi način rada u avionu"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> želi dodati sljedeću karticu u Brze postavke"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Dodaj karticu"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplikacija je aktivna}one{# aplikacija je aktivna}few{# aplikacije su aktivne}other{# aplikacija je aktivno}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nove informacije"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivne aplikacije"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ove aplikacije su aktivne i pokrenute, čak i kada ih ne koristite. Ovim se poboljšava njihova funkcionalnost, ali može uticati i na vijek trajanja baterije."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ove aplikacije su aktivne i pokrenute, čak i kada ih ne koristite. Ovim se poboljšava njihova funkcionalnost, ali to može uticati i na vijek trajanja baterije."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zaustavi"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zaustavljeno"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gotovo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sklopljeno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otklopljeno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterija pisaljke <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Baterija pisaljke je slaba"</string>
<string name="video_camera" msgid="7654002575156149298">"Video kamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona proširivanja"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tastature"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index a82d6f1..5afad1b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Torna\'l a activar automàticament demà"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Les funcions com Quick Share i Troba el meu dispositiu utilitzen el Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth s\'activarà demà al matí"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartició d\'àudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"S\'està compartint l\'àudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Àudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculars"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"L\'experiència amb el dispositiu s\'ha vist afectada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipus de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravació de pantalla"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendiment"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfície d\'usuari"</string>
+ <string name="thermal" msgid="6758074791325414831">"Tèrmic"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode d\'una mà"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audiòfons"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actiu"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconnectat"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audiòfons"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincula un dispositiu nou"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fes clic per vincular un dispositiu nou"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria del llapis òptic: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connecta el llapis òptic a un carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria del llapis òptic baixa"</string>
<string name="video_camera" msgid="7654002575156149298">"Càmera de vídeo"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Desplega la icona"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroil·luminació del teclat"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivell %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controls de la llar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 9b540ff..b5293c0 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Zítra znovu automaticky zapnout"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth využívají funkce jako Quick Share a Najdi moje zařízení."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se zapne zítra ráno."</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Sdílení zvuku"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sdílení zvuku"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Sluchátka"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Co v zařízení bylo ovlivněno?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte druh problém"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Záznam obrazovky"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Výkon"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Uživatelské rozhraní"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termovize"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jedné ruky"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Naslouchátka"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivní"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Odpojeno"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Naslouchátka"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovat nové zařízení"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zařízení"</string>
@@ -923,7 +920,7 @@
<string name="mobile_data" msgid="4564407557775397216">"Mobilní data"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
- <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi je vypnuta"</string>
+ <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi je vypnutá"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth je vypnuto"</string>
<string name="dnd_is_off" msgid="3185706903793094463">"Režim Nerušit je vypnut"</string>
<string name="dnd_is_on" msgid="7009368176361546279">"Režim Nerušit je zapnutý"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Aplikace běžící na pozadí"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Klepnutím zobrazíte podrobnosti o využití baterie a dat"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vypnout mobilní data?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Prostřednictvím <xliff:g id="CARRIER">%s</xliff:g> nebudete moci používat data ani internet. Internet bude dostupný pouze přes Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Prostřednictvím operátora <xliff:g id="CARRIER">%s</xliff:g> nebudete moct používat data ani internet. Internet bude dostupný pouze přes Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vašeho operátora"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Přepnout zpět na operátora <xliff:g id="CARRIER">%s</xliff:g>?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Mobilní data se nebudou automaticky přepínat podle dostupnosti"</string>
@@ -1211,7 +1208,7 @@
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nové informace"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aktivní aplikace"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Tyto aplikace jsou spuštěné a aktivní, i když je nepoužíváte. Zlepšuje to jejich funkčnost, ale může to mít dopad na výdrž baterie."</string>
- <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Konec"</string>
+ <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Zastavit"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Zastaveno"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Hotovo"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Zkopírováno"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"složené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterie dotykového pera <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Připojte dotykové pero k nabíječce"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Slabá baterie dotykového pera"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhledat zkratky"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sbalení"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalení"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"nebo"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvícení klávesnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Úroveň %1$d z %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládání domácnosti"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 57353f7..6e2323b 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktivér automatisk igen i morgen"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktioner som f.eks. Quick Share og Find min enhed anvender Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth aktiveres i morgen tidlig"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Lyddeling"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deler lyd"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del af din enhedsoplevelse blev påvirket?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vælg problemtype"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skærmoptagelse"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ydeevne"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Brugerflade"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termisk"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndstilstand"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivt"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Afbrudt"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Par ny enhed"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik for at parre en ny enhed"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"foldet"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"foldet ud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batteriniveau på styluspen: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Slut din styluspen til en oplader"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Lavt batteriniveau på styluspen"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Genveje til søgning"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon for Skjul"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon for Udvid"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturets baggrundslys"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d af %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemmestyring"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e7fa9b1..bf28a88 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Morgen automatisch wieder aktivieren"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktionen wie „Quick Share“ und „Mein Gerät finden“ verwenden Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth wird morgen früh aktiviert"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audiofreigabe"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audioinhalte werden freigegeben"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akkustand: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Welche Bereiche des Geräts waren betroffen?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Art des Problems auswählen"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Bildschirmaufnahme"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Leistung"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Benutzeroberfläche"</string>
+ <string name="thermal" msgid="6758074791325414831">"Überhitzung"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhandmodus"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörgeräte"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiv"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Nicht verbunden"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörgeräte"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Neues Gerät koppeln"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicken, um neues Gerät zu koppeln"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zugeklappt"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aufgeklappt"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Akkustand des Eingabestifts: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Schließe deinen Eingabestift an ein Ladegerät an"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stylus-Akkustand niedrig"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tastenkürzel suchen"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Symbol „Minimieren“"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Symbol „Maximieren“"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oder"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturbeleuchtung"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d von %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Smart-Home-Steuerung"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 23d704d..3dd5fc0 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Αυτόματη ενεργοποίηση ξανά αύριο"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Λειτουργίες όπως το Quick Share και η Εύρεση συσκευής χρησιμοποιούν το Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Το Bluetooth θα ενεργοποιηθεί αύριο το πρωί"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Κοινή χρήση ήχου"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Κοινή χρήση ήχου"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Μπαταρία <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ήχος"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ακουστικά"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ποιο κομμάτι της εμπειρίας συσκευής επηρεάστηκε;"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Επιλογή τύπου προβλήματος"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Εγγραφή οθόνης"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Απόδοση"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Διεπαφή χρήστη"</string>
+ <string name="thermal" msgid="6758074791325414831">"Θερμικό"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Λειτουργία ενός χεριού"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Συσκευές ακοής"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ενεργά"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Αποσυνδεδεμένα"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Συσκευές ακοής"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Σύζευξη νέας συσκευής"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Κάντε κλικ για σύζευξη νέας συσκευής"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"διπλωμένη"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ξεδιπλωμένη"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Μπαταρία γραφίδας <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Συνδέστε τη γραφίδα σε έναν φορτιστή"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Χαμηλή στάθμη μπαταρίας γραφίδας"</string>
<string name="video_camera" msgid="7654002575156149298">"Βιντεοκάμερα"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Συντομεύσεις αναζήτησης"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Εικονίδιο σύμπτυξης"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Εικονίδιο ανάπτυξης"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ή"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Οπίσθιος φωτισμός πληκτρολογίου"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Επίπεδο %1$d από %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Οικιακοί έλεγχοι"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d71ff1c..e830f3c 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 44e9d25..046ce28 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -281,8 +281,8 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio Sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing Audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Sharing audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1322,8 +1322,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d71ff1c..e830f3c 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d71ff1c..e830f3c 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-handed mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hearing devices"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Active"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnected"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hearing devices"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Pair new device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Click to pair new device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index c2f7098..07907a6 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -281,8 +281,8 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatically turn on again tomorrow"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Features like Quick Share and Find My Device use Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth will turn on tomorrow morning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio Sharing"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sharing Audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button" msgid="7545274861795853838">"Share audio"</string>
+ <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="3069309588231072128">"Sharing audio"</string>
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> battery"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -1322,8 +1322,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Search shortcuts"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Collapse icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index fd800ad..c622ebe 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Activar automáticamente mañana"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Las funciones como Quick Share y Encontrar mi dispositivo usan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth se activará mañana a la mañana"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Uso compartido de audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartiendo audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu exp. del disp. se vio afectada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Seleccionar tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabadora de pant."</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendimiento"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfaz de usuario"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo una mano"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo nuevo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para vincular un dispositivo nuevo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batería de la pluma stylus: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu pluma stylus a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"La pluma stylus tiene poca batería"</string>
<string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
@@ -1328,10 +1324,9 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Buscar combinaciones de teclas"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícono de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícono de expandir"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string>
- <string name="home_controls_dream_description" msgid="4644150952104035789">"Accede rápidamente a controles de la casa como prot. de pantalla"</string>
+ <string name="home_controls_dream_description" msgid="4644150952104035789">"Usa rápidamente los controles de la casa como protector de pantalla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5bcf582..c021b45 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Volver a activar automáticamente mañana"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Las funciones como Quick Share y Encontrar mi dispositivo usan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"El Bluetooth se activará mañana por la mañana"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartir audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartiendo audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"¿Qué parte de tu experiencia se ha visto afectada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona el tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Grabar pantalla"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendimiento"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfaz de usuario"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo Una mano"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Audífonos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Audífonos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Emparejar nuevo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Haz clic para emparejar un nuevo dispositivo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batería del lápiz óptico al <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta tu lápiz óptico a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Batería del lápiz óptico baja"</string>
<string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atajos de búsqueda"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icono de desplegar"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index e7d5e2f..003c925 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Lülita automaatselt homme uuesti sisse"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Sellised funktsioonid nagu Kiirjagamine ja Leia mu seade kasutavad Bluetoothi."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth lülitub sisse homme hommikul"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Heli jagamine"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Heli jagamine"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> akut"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Heli"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Peakomplekt"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Millist seadme kasutuskogemuse osa see mõjutas?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valige probleemi tüüp"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekraanisalvestus"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Jõudlus"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kasutajaliides"</string>
+ <string name="thermal" msgid="6758074791325414831">"Soojus"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ühekäerežiim"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuuldeseadmed"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ühendatud"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ühendus on katkestatud"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuuldeseadmed"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uue seadme sidumine"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Uue seadme sidumiseks klõpsake"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kokku volditud"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"lahti volditud"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Elektronpliiatsi aku <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ühendage elektronpliiats laadijaga"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Elektronpliiatsi akutase on madal"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokaamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Otsingu otseteed"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ahendamisikoon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laiendamisikoon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"või"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatuuri taustavalgustus"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Tase %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kodu juhtelemendid"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 5e4c5ac..66b79b8 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktibatu automatikoki berriro bihar"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share, Bilatu nire gailua eta beste eginbide batzuek Bluetootha erabiltzen dute"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bihar goizean aktibatuko da Bluetootha"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audioa partekatzea"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audioa partekatzen"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audioa"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Entzungailua"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Gailuaren erabileraren zer alderdiri eragin dio?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Hautatu arazo mota"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Pantaila-grabaketa"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Errendimendua"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Erabiltzaile-interfazea"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termikoa"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Esku bakarreko modua"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Entzumen-gailuak"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktibo"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Deskonektatuta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Entzumen-gailuak"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parekatu beste gailu bat"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Egin klik beste gailu bat parekatzeko"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"tolestuta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tolestu gabe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Arkatzaren bateria: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Konektatu arkatza kargagailu batera"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Arkatzak bateria gutxi du"</string>
<string name="video_camera" msgid="7654002575156149298">"Bideokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bilatu lasterbideak"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tolesteko ikonoa"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Zabaltzeko ikonoa"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"edo"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Teklatuaren hondoko argia"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d/%2$d maila"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Etxeko gailuen kontrola"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ad24c1b..cdbb685 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"فردا دوباره بهطور خودکار روشن شود"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ویژگیهایی مثل «همرسانی سریع» و «پیدا کردن دستگاهم» از بلوتوث استفاده میکنند"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"بلوتوث فردا صبح روشن خواهد شد"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"اشتراک صدا"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"درحال اشتراکگذاری صدا"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"شارژ باتری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"صوت"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"هدست"</string>
@@ -361,24 +363,19 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"کدام بخش تجربه استفاده از دستگاه تحتتأثیر قرار گرفت؟"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"انتخاب نوع مشکل"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ضبط صفحهنمایش"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"عملکرد"</string>
+ <string name="user_interface" msgid="3712869377953950887">"میانای کاربر"</string>
+ <string name="thermal" msgid="6758074791325414831">"حرارتی"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"حالت یکدستی"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سمعک"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"فعال"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"اتصال قطع شد"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سمعک"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"جفت کردن دستگاه جدید"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"برای جفت کردن دستگاه جدید، کلیک کنید"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"پیشتنظیم بهروزرسانی نشد"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"پیشتنظیم"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"زیرنویس زنده"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"زیرنویس ناشنوایان زنده"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"دوربین دستگاه لغو انسداد شود؟"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"دوربین و میکروفون دستگاه لغو انسداد شود؟"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"تاشده"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"تانشده"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"شارژ باتری قلم <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"قلم را به شارژر وصل کنید"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"باتری قلم ضعیف است"</string>
<string name="video_camera" msgid="7654002575156149298">"دوربین ویدیویی"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"جستجوی میانبرها"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"نماد جمع کردن"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"نماد ازهم بازکردن"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"نور پسزمینه صفحهکلید"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"سطح %1$d از %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"کنترل خانه هوشمند"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 0fed3d5..bea39cb 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Laita automaattisesti päälle taas huomenna"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share, Paikanna laite ja tietyt muut ominaisuudet käyttävät Bluetoothia"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth menee päälle huomisaamuna"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audionjako"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audiota jaetaan"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akun taso <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ääni"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Mitä osaa käyttökokemuksesta ongelma koski?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Valitse ongelman tyyppi"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Näytön tallentaja"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Suorituskyky"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Käyttöliittymä"</string>
+ <string name="thermal" msgid="6758074791325414831">"Lämpökamera"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Yhden käden moodi"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Kuulolaitteet"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiivinen"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Yhteys katkaistu"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Kuulolaitteet"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Muodosta uusi laitepari"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Muodosta uusi laitepari klikkaamalla"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"taitettu"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"taittamaton"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Näyttökynän akku <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Yhdistä näyttökynä laturiin"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Näyttökynän akku vähissä"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Laajennuskuvake"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"tai"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Näppämistön taustavalo"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Taso %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kodin ohjaus"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 95c788a..95b25936 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Activer le Bluetooth automatiquement demain"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Les fonctionnalités comme Partage rapide et Localiser mon appareil utilisent le Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Le Bluetooth s\'activera demain matin"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Partage audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Partage de l\'audio en cours…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Pile : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Écouteurs"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quelle composante de l\'appareil a été affectée?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionner un type"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement écran"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performance"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface utilisateur"</string>
+ <string name="thermal" msgid="6758074791325414831">"Thermique"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode Une main"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actives"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Déconnectées"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquez ici pour associer un nouvel appareil"</string>
@@ -1209,8 +1206,8 @@
<string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Choisir l\'utilisateur"</string>
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# application est active}one{# application est active}many{# d\'applications sont actives}other{# applications sont actives}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nouvelle information"</string>
- <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applications actives"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applications sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnalité, mais peut également affecter l\'autonomie de la pile."</string>
+ <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applis sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnalité, mais peut également affecter l\'autonomie de la pile."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Pile du stylet <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Pile du stylet faible"</string>
<string name="video_camera" msgid="7654002575156149298">"Caméra"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Recherchez des raccourcis"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Domotique"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b7abd0e..1b8ddc1 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Réactiver automatiquement demain"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Certaines fonctionnalités, telles que Quick Share et Localiser mon appareil, utilisent le Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Le Bluetooth sera activé demain matin"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Partage audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio partagé"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batterie"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Casque"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Quel problème avez-vous rencontré avec votre appareil ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sélectionnez un type de problème"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Enregistrement de l\'écran"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performances"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface utilisateur"</string>
+ <string name="thermal" msgid="6758074791325414831">"Thermique"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode une main"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Appareils auditifs"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actifs"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Déconnectés"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Appareils auditifs"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Associer un nouvel appareil"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Cliquer pour associer un nouvel appareil"</string>
@@ -1212,7 +1209,7 @@
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Applis actives"</string>
<string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Ces applis sont actives et s\'exécutent même lorsque vous ne les utilisez pas. Cela améliore leur fonctionnement, mais peut également affecter l\'autonomie de la batterie."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Arrêter"</string>
- <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêtée"</string>
+ <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Arrêté"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"OK"</string>
<string name="clipboard_overlay_text_copied" msgid="1872624400464891363">"Copié"</string>
<string name="clipboard_edit_source" msgid="9156488177277788029">"De <xliff:g id="APPNAME">%1$s</xliff:g>"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batterie du stylet à <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connectez votre stylet à un chargeur"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"La batterie du stylet est faible"</string>
<string name="video_camera" msgid="7654002575156149298">"Caméra"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Raccourcis de recherche"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icône Réduire"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icône Développer"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d sur %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Contrôle de la maison"</string>
diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
index 23c124c..fcdd9f0 100644
--- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml
@@ -58,8 +58,8 @@
</string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"Indisponible"</item>
- <item msgid="5044688398303285224">"Désactivée"</item>
- <item msgid="8527389108867454098">"Activée"</item>
+ <item msgid="5044688398303285224">"Désactivé"</item>
+ <item msgid="8527389108867454098">"Activé"</item>
</string-array>
<string-array name="tile_states_rotation">
<item msgid="4578491772376121579">"Indisponible"</item>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 55dd05a..1d0f4c4 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Volver activar automaticamente mañá"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"As funcións como Quick Share e Localizar o meu dispositivo utilizan o Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth activarase mañá á mañá"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio compartido"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartindo audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de batería"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auriculares"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cal foi o problema na experiencia co dispositivo?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecciona o tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravación de pant."</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Rendemento"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface de usuario"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo dunha soa man"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Vincular dispositivo novo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic para vincular un novo dispositivo"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dispositivo pregado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dispositivo despregado"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batería do lapis óptico: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecta o lapis óptico a un cargador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"O lapis óptico ten pouca batería"</string>
<string name="video_camera" msgid="7654002575156149298">"Videocámara"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atallos de busca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona de contraer"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona de despregar"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controis domóticos"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 425a768..7a4cfd1 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"આવતીકાલે ફરીથી ઑટોમૅટિક રીતે ચાલુ કરો"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ક્વિક શેર અને Find My Device જેવી સુવિધાઓ બ્લૂટૂથનો ઉપયોગ કરે છે"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"બ્લૂટૂથ આવતીકાલે સવારે ચાલુ થશે"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ઑડિયો શેરિંગ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ઑડિયો શેર કરી રહ્યાં છીએ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> બૅટરી"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ઑડિયો"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"હૅડસેટ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ડિવાઇસ સંબંધી તમારા અનુભવના કયા ભાગને અસર થઈ હતી?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"સમસ્યાનો પ્રકાર પસંદ કરો"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"સ્ક્રીન રેકોર્ડ કરો"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"પર્ફોર્મન્સ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"યૂઝર ઇન્ટરફેસ"</string>
+ <string name="thermal" msgid="6758074791325414831">"થર્મલ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"એક-હાથે વાપરો મોડ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"સક્રિય"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ડિસ્કનેક્ટેડ છે"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"સાંભળવામાં મદદ આપતા ડિવાઇસ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"નવા ડિવાઇસ સાથે જોડાણ કરો"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"નવા ડિવાઇસ સાથે જોડાણ કરવા માટે ક્લિક કરો"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ફોલ્ડ કરેલું"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"અનફોલ્ડ કરેલું"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"સ્ટાઇલસની બૅટરી <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"તમારા સ્ટાઇલસને ચાર્જર સાથે કનેક્ટ કરો"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"સ્ટાઇલસની બૅટરીમાં ચાર્જ ઓછો છે"</string>
<string name="video_camera" msgid="7654002575156149298">"વીડિયો કૅમેરા"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"શૉર્ટકટ શોધો"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\'મોટું કરો\'નું આઇકન"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"અથવા"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"કીબોર્ડની બૅકલાઇટ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dમાંથી %1$d લેવલ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ઘરેલું સાધનોના નિયંત્રણો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8f7b87c..896af24 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"कल फिर से अपने-आप चालू हो जाए"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक शेयर और Find My Device जैसी सुविधाएं, ब्लूटूथ का इस्तेमाल करती हैं"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लूटूथ कल सुबह चालू होगा"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ऑडियो शेयर करने की सुविधा"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ऑडियो शेयर किया जा रहा है"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> बैटरी"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडियो"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"आपके डिवाइस की कौनसी सुविधा पर असर पड़ा था?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्या का टाइप चुनें"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रीन रिकॉर्डर"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"परफ़ॉर्मेंस"</string>
+ <string name="user_interface" msgid="3712869377953950887">"यूज़र इंटरफ़ेस"</string>
+ <string name="thermal" msgid="6758074791325414831">"थर्मल"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"वन-हैंडेड मोड"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"कान की मशीनें"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ऐक्टिव"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"डिसकनेक्ट हो गया"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"कान की मशीनें"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नया डिवाइस जोड़ें"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नया डिवाइस जोड़ने के लिए क्लिक करें"</string>
@@ -1112,7 +1109,7 @@
<string name="media_output_dialog_multiple_devices" msgid="1093771040315422350">"<xliff:g id="COUNT">%1$d</xliff:g> डिवाइस चुने गए"</string>
<string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(डिसकनेक्ट हो गया)"</string>
<string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"स्विच नहीं किया जा सकता. फिर से कोशिश करने के लिए टैप करें."</string>
- <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"किसी डिवाइस को कनेक्ट करें"</string>
+ <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"कोई डिवाइस कनेक्ट करें"</string>
<string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"इस सेशन को कास्ट करने के लिए, कृपया ऐप्लिकेशन खोलें."</string>
<string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"अनजान ऐप्लिकेशन"</string>
<string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"कास्ट करना बंद करें"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"डिवाइस फ़ोल्ड किया गया"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"डिवाइस अनफ़ोल्ड किया गया"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"स्टाइलस की बैटरी <xliff:g id="PERCENTAGE">%s</xliff:g> है"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"अपने स्टाइलस को चार्ज करें"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलस की बैटरी कम है"</string>
<string name="video_camera" msgid="7654002575156149298">"वीडियो कैमरा"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"सर्च शॉर्टकट"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"छोटा करने का आइकॉन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"बड़ा करने का आइकॉन"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"या"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड की बैकलाइट"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d में से %1$d लेवल"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bc84c1d..acf253d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatski uključi ponovno sutra"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Značajke kao što su brzo dijeljenje i Pronađi moj uređaj koriste Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth će se uključiti sutra ujutro"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Zajedničko slušanje"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Zajedničko slušanje"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> baterije"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalice"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na koji dio doživljaja na uređaju to utjecalo?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Odaberite vrstu problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snimanje zaslona"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Izvedba"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Korisničko sučelje"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termalno"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Način rada jednom rukom"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušna pomagala"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Nije povezano"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušna pomagala"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili novi uređaj"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zatvoreno"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otvoreno"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterija olovke <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Priključite pisaljku na punjač"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Slaba baterija pisaljke"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za proširivanje"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ili"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tipkovnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Razina %1$d od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Upravljanje uređajima"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4b36026..c73511e 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatikus visszakapcsolás holnap"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Egyes funkciók (például a Quick Share és a Készülékkereső) Bluetootht használnak"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"A Bluetooth holnap reggel bekapcsol"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Hang megosztása"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Hang megosztása…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akkumulátor: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hang"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -292,7 +294,7 @@
<string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
<string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
- <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Képernyővédő"</string>
+ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Képernyőkímélő"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Hozzáférés a kamerához"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonelérés"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Rendelkezésre áll"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Az eszközhasználati élmény mely része érintett?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Problématípus kiválasztása"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Képernyőrögzítés"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Teljesítmény"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kezelőfelület"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termikus"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Egykezes mód"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hallókészülékek"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktív"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Leválasztva"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hallókészülékek"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Új eszköz párosítása"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kattintson új eszköz párosításához"</string>
@@ -601,7 +598,7 @@
<string name="screen_pinning_exit" msgid="4553787518387346893">"Alkalmazás kitűzése megszüntetve"</string>
<string name="stream_voice_call" msgid="7468348170702375660">"Telefonhívás"</string>
<string name="stream_system" msgid="7663148785370565134">"Rendszer"</string>
- <string name="stream_ring" msgid="7550670036738697526">"Csörgetés"</string>
+ <string name="stream_ring" msgid="7550670036738697526">"Csörgés"</string>
<string name="stream_music" msgid="2188224742361847580">"Média"</string>
<string name="stream_alarm" msgid="16058075093011694">"Ébresztő"</string>
<string name="stream_notification" msgid="7930294049046243939">"Értesítés"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"összehajtva"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kihajtva"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Érintőceruza töltöttségi szintje: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tegye töltőre az érintőceruzát"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Az érintőceruza töltöttsége alacsony"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Billentyűparancsok keresése"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Összecsukás ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kibontás ikon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vagy"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"A billentyűzet háttérvilágítása"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Fényerő: %2$d/%1$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Otthon vezérlése"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d8e36ad..f1462be 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Վաղը նորից ավտոմատ միացնել"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth-ն օգտագործում են, օրինակ, Quick Share և «Գտնել իմ սարքը» գործառույթները"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-ը կմիանա վաղն առավոտյան"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Աուդիոյի փոխանցում"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Աուդիոն փոխանցվում է"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Աուդիո"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ականջակալ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Սարքի ո՞ր մասի հետ է կապված խնդիրը։"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Ընտրեք խնդրի տեսակը"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Էկրանի տեսագրում"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Արդյունավետություն"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Օգտատիրական ինտերֆեյս"</string>
+ <string name="thermal" msgid="6758074791325414831">"Ջերմատեսիլ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Մեկ ձեռքի ռեժիմ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Լսողական սարքեր"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ակտիվ է"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Անջատված է"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Լսողական սարքեր"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Նոր սարքի զուգակցում"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Սեղմեք՝ նոր սարք զուգակցելու համար"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ծալված"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"բացված"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Ստիլուսի մարտկոցի լիցքը՝ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ձեր ստիլուսը միացրեք լիցքավորիչի"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ստիլուսի մարտկոցի լիցքի ցածր մակարդակ"</string>
<string name="video_camera" msgid="7654002575156149298">"Տեսախցիկ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Դյուրանցումների որոնում"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ծալել պատկերակը"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ծավալել պատկերակը"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"կամ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Հետին լուսավորությամբ ստեղնաշար"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d՝ %2$d-ից"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Տան կառավարման տարրեր"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 22d0de5..7525e9a 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Otomatis aktifkan lagi besok"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Fitur seperti Quick Share dan Temukan Perangkat Saya menggunakan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth akan dinyalakan besok pagi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Berbagi Audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Berbagi Audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bagian pengalaman perangkat mana yang terpengaruh?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Perekaman layar"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performa"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Antarmuka Pengguna"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mode satu tangan"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Alat bantu dengar"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktif"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Terputus"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Alat bantu dengar"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sambungkan perangkat baru"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menyambungkan perangkat baru"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ditutup"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dibuka"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Baterai stilus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hubungkan stilus ke pengisi daya"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Baterai stilus lemah"</string>
<string name="video_camera" msgid="7654002575156149298">"Kamera video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan penelusuran"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikon ciutkan"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikon luaskan"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Lampu latar keyboard"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Tingkat %1$d dari %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrol Rumah"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index b631c47..3850790 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Kveikja sjálfkrafa aftur á morgun"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Eiginleikar eins og Flýtideiling og Finna tækið mitt nota Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Kveikt verður á Bluetooth í fyrramálið"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Hljóði deilt"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deilir hljóði"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> rafhlöðuhleðsla"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Hljóð"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Höfuðtól"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvað í tækjaupplifuninni varð fyrir áhrifum?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Veldu gerð vandamáls"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjáupptaka"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Afköst"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Notandaviðmót"</string>
+ <string name="thermal" msgid="6758074791325414831">"Varmi"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Einhent stilling"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Heyrnartæki"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Virk"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Aftengd"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Heyrnartæki"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Para nýtt tæki"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Smelltu til að para nýtt tæki"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"samanbrotið"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opið"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Pennarafhlaða <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Tengdu pennann við hleðslutæki"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Rafhlaða pennans er að tæmast"</string>
<string name="video_camera" msgid="7654002575156149298">"Kvikmyndatökuvél"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leitarflýtileiðir"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Stækka tákn"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eða"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Baklýsing lyklaborðs"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Stig %1$d af %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Heimastýringar"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 5494b16..a0d54c267 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Riattiva automaticamente domani"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funzionalità come Quick Share e Trova il mio dispositivo usano il Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Il Bluetooth verrà attivato domani mattina"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Condivisione audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Condivisione audio in corso…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batteria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Auricolare"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modalità a una mano"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Apparecchi acustici"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Attivi"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Disconnessi"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Protesi uditive"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Accoppia nuovo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Fai clic per accoppiare un nuovo dispositivo"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Scorciatoie per la ricerca"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icona Espandi"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"oppure"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroilluminazione della tastiera"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Livello %1$d di %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controlli della casa"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2ad95fb..f773b84 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -278,11 +278,13 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"נשמר"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ניתוק"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"הפעלה"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"החיבור יופעל שוב אוטומטית מחר"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"יופעל שוב אוטומטית מחר"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"תכונות כמו \'שיתוף מהיר\' ו\'איפה המכשיר שלי\' משתמשות ב-Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"חיבור ה-Bluetooth יופעל מחר בבוקר"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"שיתוף אודיו"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"מתבצע שיתוף של האודיו"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> סוללה"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"אודיו"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"אוזניות"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"תרמי"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"מצב שימוש ביד אחת"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"מכשירי שמיעה"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"פעיל"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"מנותק"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"מכשירי שמיעה"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"התאמה של מכשיר חדש"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"צריך ללחוץ כדי להתאים מכשיר חדש"</string>
@@ -620,7 +620,7 @@
<string name="volume_panel_noise_control_title" msgid="7413949943872304474">"בקרת רעש"</string>
<string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"אודיו מרחבי"</string>
<string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"השבתה"</string>
- <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"מצב קבוע"</string>
+ <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"מצב סטטי"</string>
<string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"מעקב אחר תנועות הראש"</string>
<string name="volume_ringer_change" msgid="3574969197796055532">"יש להקיש כדי לשנות את מצב תוכנת הצלצול"</string>
<string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string>
@@ -1198,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"ה-Wi-Fi לא יתחבר באופן אוטומטי בינתיים"</string>
<string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"כדי לעבור בין רשתות, צריך לנתק את האתרנט"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"כדי לשפר את חוויית השימוש במכשיר, אפליקציות ושירותים יוכלו לחפש רשתות Wi-Fi בכל שלב, גם כאשר ה-Wi-Fi כבוי. אפשר לשנות זאת בהגדרות של חיפוש נקודות Wi-Fi. "<annotation id="link">"שינוי"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"כדי לשפר את חוויית השימוש במכשיר, אפליקציות ושירותים יוכלו לחפש רשתות Wi-Fi בכל שלב, גם כאשר ה-Wi-Fi כבוי. אפשר לשנות את זה בהגדרות של חיפוש נקודות Wi-Fi. "<annotation id="link">"שינוי"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"השבתה של מצב טיסה"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"אפליקציית <xliff:g id="APPNAME">%1$s</xliff:g> מבקשת להוסיף להגדרות המהירות את הלחצן הבא"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"להוסיף לחצן"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"קיצורי דרך לחיפוש"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"סמל הכיווץ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"סמל ההרחבה"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"או"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"התאורה האחורית במקלדת"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"רמה %1$d מתוך %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"שליטה במכשירים"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 15c1f8b..6b5d082 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明日自動的に ON に戻す"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share や「デバイスを探す」などの機能は Bluetooth を使用します"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"明日の朝に Bluetooth が ON になります"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音声の共有"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"音声を共有中"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"バッテリー <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"オーディオ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ヘッドセット"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"温度"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"片手モード"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"補聴器"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"アクティブ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"未接続"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"補聴器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"新しいデバイスとペア設定"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"クリックすると、新しいデバイスをペア設定できます"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"検索ショートカット"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"または"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"キーボード バックライト"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"レベル %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ホーム コントロール"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4d17179..399c1f0 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ხელახლა ავტომატურად ჩართვა ხვალ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ისეთი ფუნქციები, როგორიცაა სწრაფი გაზიარება და ჩემი მოწყობილობის პოვნა, იყენებს Bluetooth-ს"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ჩაირთვება ხვალ დილით"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"აუდიოს გაზიარება"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"აუდიოს გაზიარება"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ბატარეა"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"აუდიო"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ყურსაცვამი"</string>
@@ -366,16 +368,14 @@
<string name="thermal" msgid="6758074791325414831">"თერმული"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ცალი ხელის რეჟიმი"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"სმენის აპარატები"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"აქტიური"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"კავშირი გაწყვეტილია"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"სმენის აპარატები"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ახალი მოწყობილობის დაწყვილება"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"დააწკაპუნეთ ახალი მოწყობილობის დასაწყვილებლად"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"წინასწარ დაყენებული პარამეტრების განახლება ვერ მოხერხდა"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"წინასწარ დაყენებული"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"პირდაპირი სუბტიტრები"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"ავტოსუბტიტრები"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"გსურთ მოწყობილობის კამერის განბლოკვა?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"გსურთ მოწყობილობის კამერის და მიკროფონის განბლოკვა?"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ძიების მალსახმობები"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ხატულის გაფართოება"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ან"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"კლავიატურის შენათება"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"დონე: %1$d %2$d-დან"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"სახლის კონტროლი"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 08e9fa2..a3e6179 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ертең автоматты түрде қосылсын"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share және Find My Device сияқты функциялар Bluetooth-ты пайдаланады."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ертең таңертең қосылады."</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Аудио бөлісу"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Аудио бөлісу әрекеті орындалып жатыр."</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батарея деңгейі: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Aудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Құрылғы қызметінің қандай түріне әсер етті?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Мәселе түрін таңдаңыз."</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экранды жазу"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Өнімділік режимі"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Пайдаланушы интерфейсі"</string>
+ <string name="thermal" msgid="6758074791325414831">"Термовизия"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бір қолмен басқару режимі"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Есту құрылғылары"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Қосулы"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ажыратулы"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Есту құрылғылары"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңа құрылғыны жұптау"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңа құрылғыны жұптау үшін басыңыз."</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"жабық"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ашық"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Стилус батареясы: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусты зарядтағышқа жалғаңыз."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Стилус батареясының заряды аз"</string>
<string name="video_camera" msgid="7654002575156149298">"Бейнекамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Іздеу жылдам пәрмендері"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"немесе"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Пернетақта жарығы"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Деңгей: %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Үй басқару элементтері"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index d6538bd..7c6f127 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"បើកដោយស្វ័យប្រវត្តិម្ដងទៀតនៅថ្ងៃស្អែក"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"មុខងារដូចជា Quick Share និង \"រកឧបករណ៍របស់ខ្ញុំ\" ប្រើប៊្លូធូស"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ប៊្លូធូសនឹងបើកនៅព្រឹកស្អែក"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ការស្ដាប់សំឡេងរួមគ្នា"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"កំពុងស្ដាប់សំឡេងរួមគ្នា"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"សំឡេង"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"កាស"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"តើផ្នែកអ្វីនៃបទពិសោធប្រើប្រាស់ឧបករណ៍របស់អ្នកបានរងការប៉ះពាល់?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ជ្រើសរើសប្រភេទបញ្ហា"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ការថតវីដេអូអេក្រង់"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ប្រតិបត្តិការ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ផ្ទៃប៉ះ"</string>
+ <string name="thermal" msgid="6758074791325414831">"កម្ដៅ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"មុខងារប្រើដៃម្ខាង"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"សកម្ម"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"បានផ្ដាច់"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ផ្គូផ្គងឧបករណ៍ថ្មី"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ចុច ដើម្បីផ្គូផ្គងឧបករណ៍ថ្មី"</string>
@@ -1201,7 +1198,7 @@
<string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិក្នុងពេលនេះទេ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"មើលទាំងអស់"</string>
<string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"ដើម្បីប្ដូរបណ្ដាញ សូមផ្ដាច់អ៊ីសឺរណិត"</string>
- <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ដើម្បីធ្វើឱ្យបទពិសោធន៍ប្រើប្រាស់ឧបករណ៍ប្រសើរឡើង កម្មវិធី និងសេវាកម្មនៅតែអាចស្កេនរកបណ្ដាញ Wi‑Fi បានគ្រប់ពេល ទោះបីជានៅពេលដែលបិទ Wi‑Fi ក៏ដោយ។ អ្នកអាចប្ដូរវាបាននៅក្នុងការកំណត់ការស្កេន Wi‑Fi។ "<annotation id="link">"ប្ដូរ"</annotation></string>
+ <string name="wifi_scan_notify_message" msgid="3753839537448621794">"ដើម្បីធ្វើឱ្យបទពិសោធប្រើប្រាស់ឧបករណ៍ប្រសើរឡើង កម្មវិធី និងសេវាកម្មនៅតែអាចស្កេនរកបណ្ដាញ Wi‑Fi បានគ្រប់ពេល ទោះបីជានៅពេលដែលបិទ Wi‑Fi ក៏ដោយ។ អ្នកអាចប្ដូរវាបាននៅក្នុងការកំណត់ការស្កេន Wi‑Fi។ "<annotation id="link">"ប្ដូរ"</annotation></string>
<string name="turn_off_airplane_mode" msgid="8425587763226548579">"បិទមុខងារពេលជិះយន្តហោះ"</string>
<string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ចង់បញ្ចូលប្រអប់ខាងក្រោមទៅក្នុងការកំណត់រហ័ស"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"បញ្ចូលប្រអប់"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"បត់"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"លា"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ថ្មប៊ិក <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ភ្ជាប់ប៊ិករបស់អ្នកជាមួយឆ្នាំងសាក"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ថ្មប៊ិកនៅសល់តិច"</string>
<string name="video_camera" msgid="7654002575156149298">"កាមេរ៉ាវីដេអូ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ផ្លូវកាត់ការស្វែងរក"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"រូបតំណាង \"ពង្រីក\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ឬ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ពន្លឺក្រោយក្ដារចុច"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"កម្រិតទី %1$d នៃ %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ការគ្រប់គ្រងផ្ទះ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 92a8b6b..31aa875 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ನಾಳೆ ಪುನಃ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಆನ್ ಮಾಡಿ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ಕ್ವಿಕ್ ಶೇರ್ ಮತ್ತು Find My Device ನಂತಹ ಫೀಚರ್ಗಳು ಬ್ಲೂಟೂತ್ ಅನ್ನು ಬಳಸುತ್ತವೆ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ಬ್ಲೂಟೂತ್ ನಾಳೆ ಬೆಳಗ್ಗೆ ಆನ್ ಆಗುತ್ತದೆ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ಆಡಿಯೋವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ಬ್ಯಾಟರಿ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ಆಡಿಯೋ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ಹೆಡ್ಸೆಟ್"</string>
@@ -361,24 +363,19 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ಸಾಧನ ಬಳಸುವಾಗ ನೀವು ಯಾವ ರೀತಿಯ ಸಮಸ್ಯೆ ಎದುರಿಸುತ್ತೀರಿ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ಸಮಸ್ಯೆಯ ಪ್ರಕಾರವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ಪರ್ಫಾರ್ಮೆನ್ಸ್"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ಬಳಕೆದಾರ ಇಂಟರ್ಫೇಸ್"</string>
+ <string name="thermal" msgid="6758074791325414831">"ಥರ್ಮಲ್"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ಒಂದು ಕೈ ಮೋಡ್"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ಸಕ್ರಿಯವಾಗಿದೆ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ಡಿಸ್ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ಹೊಸ ಸಾಧನವನ್ನು ಪೇರ್ ಮಾಡಿ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"ಪ್ರಿಸೆಟ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"ಪ್ರಿಸೆಟ್"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"ಲೈವ್ ಶೀರ್ಷಿಕೆ"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"ಲೈವ್ ಕ್ಯಾಪ್ಶನ್"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"ಸಾಧನದ ಕ್ಯಾಮರಾ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"ಸಾಧನದ ಕ್ಯಾಮರಾ ಮತ್ತು ಮೈಕ್ರೋಫೋನ್ ಅನ್ನು ಅನ್ಬ್ಲಾಕ್ ಮಾಡಬೇಕೇ?"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ಅನ್ಫೋಲ್ಡ್ ಮಾಡಿರುವುದು"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ಸ್ಟೈಲಸ್ ಬ್ಯಾಟರಿ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ನಿಮ್ಮ ಸ್ಟೈಲಸ್ ಅನ್ನು ಚಾರ್ಜರ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ಸ್ಟೈಲಸ್ ಬ್ಯಾಟರಿ ಕಡಿಮೆಯಿದೆ"</string>
<string name="video_camera" msgid="7654002575156149298">"ವೀಡಿಯೊ ಕ್ಯಾಮರಾ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ಹುಡುಕಾಟದ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ಅಥವಾ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ಕೀಬೋರ್ಡ್ ಬ್ಯಾಕ್ಲೈಟ್"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ರಲ್ಲಿ %1$d ಮಟ್ಟ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ಮನೆ ನಿಯಂತ್ರಣಗಳು"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index b141b48..91266b7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"내일 다시 자동으로 사용 설정"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share, 내 기기 찾기 등의 기능에서 블루투스를 사용합니다."</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"블루투스가 내일 아침에 켜집니다."</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"오디오 공유"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"오디오 공유 중"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"배터리 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"오디오"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"헤드셋"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"기기 경험의 어떤 부분에 영향이 있었나요?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"문제 유형 선택"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"화면 녹화"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"성능"</string>
+ <string name="user_interface" msgid="3712869377953950887">"사용자 인터페이스"</string>
+ <string name="thermal" msgid="6758074791325414831">"열화상"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"한 손 사용 모드"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"청각 보조 기기"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"활성"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"연결 끊김"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"청각 보조 기기"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"새 기기와 페어링"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"새 기기와 페어링하려면 클릭하세요"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"접은 상태"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"펼친 상태"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"스타일러스 배터리 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"스타일러스를 충전기에 연결하세요"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"스타일러스 배터리 부족"</string>
<string name="video_camera" msgid="7654002575156149298">"비디오 카메라"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"검색 바로가기"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"확장 아이콘"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"또는"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"키보드 백라이트"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d단계 중 %1$d단계"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"홈 컨트롤"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index dc7227e..a3fd0a2 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Эртең автоматтык түрдө кайра күйгүзүү"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth Тез бөлүшүү жана Түзмөгүм кайда? сыяктуу функцияларда колдонулат"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth эртең таңда күйөт"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Чогуу угуу"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Чогуу угулууда"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батареянын деңгээли <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Түзмөгүңүздүн кайсы бөлүгүнө кедергиси тийди?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Маселенин түрүн тандоо"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Экрандан видео жаздырып алуу"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Иштин майнаптуулугу"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Колдонуучунун интерфейси"</string>
+ <string name="thermal" msgid="6758074791325414831">"Жылуулук"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Бир кол режими"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Угуу аппараттары"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Жигердүү"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ажыратылды"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Угуу аппараттары"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Жаңы түзмөк кошуу"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Жаңы түзмөк кошуу үчүн басыңыз"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"бүктөлгөн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ачылган"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Стилустун батареясы: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Стилусту кубаттаңыз"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Стилустун батареясы отурайын деп калды"</string>
<string name="video_camera" msgid="7654002575156149298">"Видео камера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ыкчам баскычтарды издөө"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жайып көрсөтүү сүрөтчөсү"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"же"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Баскычтоптун жарыгы"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ичинен %1$d-деңгээл"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Үйдөгү түзмөктөрдү тескөө"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 5894084..31182fd 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ເປີດໃຊ້ໂດຍອັດຕະໂນມັດອີກຄັ້ງມື້ອື່ນ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ຄຸນສົມບັດຕ່າງໆໃຊ້ Bluetooth ເຊັ່ນ: ການແຊຣ໌ດ່ວນ ແລະ ຊອກຫາອຸປະກອນຂອງຂ້ອຍ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ຈະເປີດມື້ອື່ນເຊົ້າ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ການແບ່ງປັນສຽງ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ກຳລັງແບ່ງປັນສຽງ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ສຽງ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ຊຸດຫູຟັງ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ສ່ວນໃດຂອງປະສົບການອຸປະກອນຂອງທ່ານໄດ້ຮັບຜົນກະທົບ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ເລືອກປະເພດບັນຫາ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ບັນທຶກໜ້າຈໍ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ປະສິດທິພາບ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ສ່ວນຕິດຕໍ່ຜູ້ໃຊ້"</string>
+ <string name="thermal" msgid="6758074791325414831">"ຄວາມຮ້ອນ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ໂໝດມືດຽວ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ອຸປະກອນຊ່ວຍຟັງ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ນຳໃຊ້ຢູ່"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ອຸປະກອນຊ່ວຍຟັງ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ຈັບຄູ່ອຸປະກອນໃໝ່"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ຄລິກເພື່ອຈັບຄູ່ອຸປະກອນໃໝ່"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ພັບແລ້ວ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ກາງອອກແລ້ວ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ແບັດເຕີຣີປາກກາ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ເຊື່ອມຕໍ່ປາກກາຂອງທ່ານກັບສາຍສາກ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ແບັດເຕີຣີປາກກາເຫຼືອໜ້ອຍ"</string>
<string name="video_camera" msgid="7654002575156149298">"ກ້ອງວິດີໂອ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ທາງລັດການຊອກຫາ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ໄອຄອນຫຍໍ້ລົງ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ໄອຄອນຂະຫຍາຍ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ຫຼື"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ໄຟປຸ່ມແປ້ນພິມ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"ລະດັບທີ %1$d ຈາກ %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ການຄວບຄຸມເຮືອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 2c9eed8..62c2911 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatiškai vėl įjungti rytoj"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Tokioms funkcijoms kaip „Spartusis bendrinimas“ ir „Rasti įrenginį“ naudojamas „Bluetooth“ ryšys"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"„Bluetooth“ ryšys bus įjungtas rytoj ryte"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Garso įrašų bendrinimas"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Bendrinamas garso įrašas"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumuliatorius: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Garsas"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Virtualiosios realybės įrenginys"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuri įrenginio funkcija buvo paveikta?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pasirinkite problemos tipą"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrano įrašas"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Našumas"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Naudotojo sąsaja"</string>
+ <string name="thermal" msgid="6758074791325414831">"Šiluminis"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienos rankos režimas"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Klausos įrenginiai"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktyvus"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Atjungtas"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Klausos įrenginiai"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Susieti naują įrenginį"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Spustelėkite, kad susietumėte naują įrenginį"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sulenkta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"nesulenkta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Liko rašiklio akumuliatoriaus energijos: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Prijunkite rašiklį prie kroviklio"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Senka rašiklio akumuliatorius"</string>
<string name="video_camera" msgid="7654002575156149298">"Vaizdo kamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Paieškos šaukiniai"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sutraukimo piktograma"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Išskleidimo piktograma"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"arba"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatūros foninis apšvietimas"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d lygis iš %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Namų sistemos valdymas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 6a5d068..8d0b43c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automātiski atkal ieslēgt rīt"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Tādas funkcijas kā “Ātrā kopīgošana” un “Atrast ierīci” izmanto Bluetooth savienojumu"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth savienojums tiks ieslēgts rīt no rīta"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Kopīgot audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Notiek audio kopīgošana"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Akumulators: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Austiņas"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuras ierīces funkcijas tika ietekmētas?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Atlasiet problēmas veidu"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekrāna ierakstīšana"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Veiktspēja"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Lietotāja saskarne"</string>
+ <string name="thermal" msgid="6758074791325414831">"Ierīces temperatūra"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Vienas rokas režīms"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dzirdes aparāti"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktīvs"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Atvienots"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dzirdes aparāti"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Savienot pārī jaunu ierīci"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Noklikšķiniet, lai savienotu pārī jaunu ierīci"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"aizvērta"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"atvērta"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Skārienekrāna pildspalvas akumulatora uzlādes līmenis: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pievienojiet skārienekrāna pildspalvu lādētājam"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Zems skārienekrāna pildspalvas akumulatora līmenis"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Meklēšanas saīsnes"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Sakļaušanas ikona"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Izvēršanas ikona"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"vai"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastatūras fona apgaismojums"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Līmenis numur %1$d, kopā ir %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Mājas kontrolierīces"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 7c41096..1c889e6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Автоматски вклучи повторно утре"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Функциите како „Брзо споделување“ и „Најди го мојот уред“ користат Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ќе се вклучи утре наутро"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Споделување аудио"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Се споделува аудио"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалки"</string>
@@ -301,7 +303,7 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string>
- <string name="quick_settings_networks_available" msgid="1875138606855420438">"Мрежите се достапни"</string>
+ <string name="quick_settings_networks_available" msgid="1875138606855420438">"Достапни се мрежи"</string>
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Не се достапни мрежи"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Нема достапни Wi-Fi мрежи"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Се вклучува…"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Кој дел од доживувањето на уредот беше засегнат?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Изберете тип проблем"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Снимање екран"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Изведба"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Кориснички интерфејс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Термално"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим со една рака"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Не е поврзано"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Спари нов уред"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликнете за да спарите нов уред"</string>
@@ -689,8 +686,8 @@
<string name="notification_automatic_title" msgid="3745465364578762652">"Автоматски"</string>
<string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибрации"</string>
<string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибрации и се појавува подолу во делот со разговори"</string>
- <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да ѕвони или вибрира во зависност од поставките за уредот"</string>
- <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да ѕвони или вибрира во зависност од поставките на уредот. Стандардно, разговорите од <xliff:g id="APP_NAME">%1$s</xliff:g> се во балончиња."</string>
+ <string name="notification_channel_summary_default" msgid="777294388712200605">"Може да ѕвони или да вибрира во зависност од поставките за уредот"</string>
+ <string name="notification_channel_summary_default_with_bubbles" msgid="3482483084451555344">"Може да ѕвони или да вибрира во зависност од поставките за уредот. Стандардно, разговорите од <xliff:g id="APP_NAME">%1$s</xliff:g> се во балончиња."</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Дозволете системот да определи дали известувањево треба да испушти звук или да вибрира"</string>
<string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"<b>Статус:</b> поставено на „Стандардно“"</string>
<string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"<b>Статус:</b> намалено на „Тивко“"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{Активна е # апликација}one{Активни се # апликација}other{Активни се # апликации}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Нови информации"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Активни апликации"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Овие апликации се активни и работат, дури и кога не ги користите. Ова ја подобрува нивната функционалност, но може да влијае и на траењето на батеријата."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Овие апликации се активни и работат дури и кога не ги користите. Ова ја подобрува нивната функционалност, но може и да влијае на траењето на батеријата."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Запри"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Запрено"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Готово"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворен"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворен"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Батерија на пенкало: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поврзете го пенкалото со полнач"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Слаба батерија на пенкало"</string>
<string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Кратенки за пребарување"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за собирање"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширување"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Осветлување на тастатура"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d од %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за домот"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 540358c..3dd91f7 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"നാളെ വീണ്ടും സ്വയമേവ ഓണാക്കുക"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ക്വിക്ക് ഷെയർ, Find My Device പോലുള്ള ഫീച്ചറുകൾ Bluetooth ഉപയോഗിക്കുന്നു"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth നാളെ രാവിലെ ഓണാകും"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ഓഡിയോ പങ്കിടൽ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ഓഡിയോ പങ്കിടുന്നു"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ബാറ്ററി"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ഓഡിയോ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ഹെഡ്സെറ്റ്"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"നിങ്ങളുടെ ഉപകരണ അനുഭവത്തിന്റെ ഏത് ഭാഗമാണ് ബാധിച്ചത്?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"പ്രശ്ന തരം തിരഞ്ഞെടുക്കുക"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"സ്ക്രീൻ റെക്കോർഡ്"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"പ്രകടനം"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ഉപയോക്തൃ ഇന്റർഫേസ്"</string>
+ <string name="thermal" msgid="6758074791325414831">"തെർമൽ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ഒറ്റക്കൈ മോഡ്"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"സജീവം"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"വിച്ഛേദിച്ചിരിക്കുന്നു"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"കേൾവിക്കുള്ള ഉപകരണങ്ങൾ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"പുതിയ ഉപകരണം ജോടിയാക്കുക"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"പുതിയ ഉപകരണം ജോടിയാക്കാൻ ക്ലിക്ക് ചെയ്യുക"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ഫോൾഡ് ചെയ്തത്"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"അൺഫോൾഡ് ചെയ്തത്"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"സ്റ്റൈലസ് ബാറ്ററി <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"നിങ്ങളുടെ സ്റ്റൈലസ് ചാർജറുമായി കണക്റ്റ് ചെയ്യുക"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"സ്റ്റൈലസിന്റെ ബാറ്ററി ചാർജ് കുറവാണ്"</string>
<string name="video_camera" msgid="7654002575156149298">"വീഡിയോ ക്യാമറ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"തിരയൽ കുറുക്കുവഴികൾ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"വികസിപ്പിക്കൽ ഐക്കൺ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"അല്ലെങ്കിൽ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"കീബോഡ് ബാക്ക്ലൈറ്റ്"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-ൽ %1$d-ാമത്തെ ലെവൽ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ഹോം കൺട്രോളുകൾ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 47e6936..5539263 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Маргааш автоматаар дахин асаах"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Түргэн хуваалцах, Миний төхөөрөмжийг олох зэрэг онцлогууд Bluetooth-г ашигладаг"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-г маргааш өглөө асаана"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Аудио хуваалцах"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Аудио хуваалцаж байна"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> батарей"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Чихэвч"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Таны төхөөрөмжийн хэрэглээний аль хэсэгт нөлөөлсөн бэ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Асуудлын төрөл сонгоно уу"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Дэлгэцийн бичлэг"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Гүйцэтгэл"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Хэрэглэгчийн интерфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Дулааны"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Нэг гарын горим"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Сонсголын төхөөрөмжүүд"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Идэвхтэй"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Салсан"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Сонсголын төхөөрөмжүүд"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Шинэ төхөөрөмж хослуулах"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Шинэ төхөөрөмж хослуулахын тулд товшино уу"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"эвхсэн"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"дэлгэсэн"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Мэдрэгч үзгийн батарей <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Мэдрэгч үзгээ цэнэглэгчтэй холбоорой"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Мэдрэгч үзэгний батарей бага байна"</string>
<string name="video_camera" msgid="7654002575156149298">"Видео камер"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Товчлолууд хайх"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Хураах дүрс тэмдэг"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"эсвэл"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Гарын арын гэрэл"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-с %1$d-р түвшин"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Гэрийн удирдлага"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 39f1413..aea4d5a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"उद्या पुन्हा आपोआप सुरू करा"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक शेअर आणि Find My Device यांसारखी वैशिष्ट्ये ब्लूटूथ वापरतात"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लूटूथ उद्या सकाळी सुरू होईल"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ऑडिओ शेअरिंग"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ऑडिओ शेअर करत आहे"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> बॅटरी"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ऑडिओ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"थर्मल"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एकहाती मोड"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"श्रवणयंत्रे"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ॲक्टिव्ह आहे"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"डिस्कनेक्ट केले आहे"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"श्रवणयंत्रे"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नवीन डिव्हाइस पेअर करा"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नवीन डिव्हाइस पेअर करण्यासाठी क्लिक करा"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शोधण्यासाठी शॉर्टकट"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"विस्तार करा आयकन"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"किंवा"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड बॅकलाइट"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d पैकी %1$d पातळी"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8fce993..0131098 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Dihidupkan lagi esok secara automatik"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Ciri seperti Quick Share dan Find My Device menggunakan Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth akan dihidupkan esok pagi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Perkongsian Audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Berkongsi Audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> bateri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Set Kepala"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Pengalaman peranti yang manakah yang terjejas?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Pilih jenis masalah"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rakam skrin"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Prestasi"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Antara Muka Pengguna"</string>
+ <string name="thermal" msgid="6758074791325414831">"Terma"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Mod sebelah tangan"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Peranti pendengaran"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktif"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Diputuskan sambungan"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Peranti pendengaran"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Gandingkan peranti baharu"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik untuk menggandingkan peranti baharu"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"terlipat"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tidak terlipat"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateri stilus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Sambungkan stilus anda kepada pengecas"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateri stilus lemah"</string>
<string name="video_camera" msgid="7654002575156149298">"Kamera video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Cahaya latar papan kekunci"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Tahap %1$d daripada %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kawalan Rumah"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 9264261..9b19b62 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"မနက်ဖြန် အလိုအလျောက် ပြန်ဖွင့်ရန်"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"‘အမြန် မျှဝေပါ’ နှင့် Find My Device ကဲ့သို့ တူးလ်များသည် ဘလူးတုသ်သုံးသည်"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"မနက်ဖြန်နံနက်တွင် ဘလူးတုသ် ပွင့်ပါမည်"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"အော်ဒီယို မျှဝေခြင်း"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"အော်ဒီယို မျှဝေနေသည်"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ဘက်ထရီ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"အသံ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"မိုက်ခွက်ပါနားကြပ်"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"စက်အသုံးပြုမှု၏ မည်သည့်အပိုင်းကို သက်ရောက်သလဲ။"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ပြဿနာအမျိုးအစား ရွေးရန်"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ဖန်သားပြင်ရိုက်ကူးရန်"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"စွမ်းဆောင်ရည်"</string>
+ <string name="user_interface" msgid="3712869377953950887">"သုံးသူအတွက် ကြားခံစနစ်"</string>
+ <string name="thermal" msgid="6758074791325414831">"အပူဓာတ်"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"လက်တစ်ဖက်သုံးမုဒ်"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"နားကြားကိရိယာ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"သုံးနေသည်"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ချိတ်ဆက်မထားပါ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"နားကြားကိရိယာ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"စက်အသစ်တွဲချိတ်ရန်"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"စက်အသစ် တွဲချိတ်ရန် နှိပ်ပါ"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ခေါက်ထားသည်"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ဖြန့်ထားသည်"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"စတိုင်လပ်စ် ဘက်ထရီ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"စတိုင်လပ်စ်ကို အားသွင်းကိရိယာနှင့် ချိတ်ဆက်ခြင်း"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"စတိုင်လပ်စ် ဘက်ထရီ အားနည်းနေသည်"</string>
<string name="video_camera" msgid="7654002575156149298">"ဗီဒီယိုကင်မရာ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ရှာဖွေစာလုံး ဖြတ်လမ်း"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"လျှော့ပြရန် သင်္ကေတ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ပိုပြရန် သင်္ကေတ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"သို့မဟုတ်"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ကီးဘုတ်နောက်မီး"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"အဆင့် %2$d အနက် %1$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"အိမ်ထိန်းချုပ်မှုများ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9c2193e..a8befb3 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Slå på igjen i morgen automatisk"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funksjoner som Quick Share og Finn enheten min bruker Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth slås på i morgen tidlig"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Lyddeling"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Deler lyd"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Lyd"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Hodetelefoner"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Hvilken del av enhetsopplevelsen din ble påvirket?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Velg problemtype"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Skjermopptak"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ytelse"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Brukergrensesnitt"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termisk"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhåndsmodus"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Høreapparater"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiv"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Frakoblet"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Høreapparater"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Koble til en ny enhet"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klikk for å koble til en ny enhet"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"lagt sammen"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"åpen"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batteri i pekepennen: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Koble pekepennen til en lader"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Det er lite batteri i pekepennen"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snarveier til søk"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Skjul-ikon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Vis-ikon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrunnslys for tastatur"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemkontroller"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 94b197b..c26ea3e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"भोलि फेरि स्वतः अन गर्नुहोस्"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"क्विक सेयर र Find My Device जस्ता सुविधाहरू प्रयोग गर्न ब्लुटुथ चाहिन्छ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ब्लुटुथ भोलि बिहान अन हुने छ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"अडियो सेयरिङ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"अडियो सेयर गरिँदै छ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ब्याट्री"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"अडियो"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"हेडसेट"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"तपाईंको डिभाइसको कुन चाहिँ सुविधा प्रभावित भएको छ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"समस्याको प्रकार चयन गर्नुहोस्"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"स्क्रिन रेकर्ड"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"पर्फर्मेन्स"</string>
+ <string name="user_interface" msgid="3712869377953950887">"युजर इन्टरफेस"</string>
+ <string name="thermal" msgid="6758074791325414831">"थर्मल"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"एक हाते मोड"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"हियरिङ डिभाइसहरू"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"सक्रिय छ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"डिस्कनेक्ट गरिएको छ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"हियरिङ डिभाइसहरू"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"नयाँ डिभाइस कनेक्ट गर्नुहोस्"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"नयाँ डिभाइसमा कनेक्ट गर्न क्लिक गर्नुहोस्"</string>
@@ -382,9 +379,9 @@
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिभाइसको माइक्रोफोन अनब्लक गर्ने हो?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"डिभाइसको क्यामेरा अनब्लक गर्ने हो?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"डिभाइसको क्यामेरा र माइक्रोफोन अनब्लक गर्ने हो?"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"यसो गर्नुभयो भने माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"यसो गर्नुभयो भने क्यामेरा प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
- <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"यसो गर्नुभयो भने क्यामेरा वा माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाहरूका लागि सो अनुमति अनब्लक गरिन्छ।"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"यसो गर्नुभयो भने माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाको हकमा यो अनुमति अनब्लक गरिन्छ।"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"यसो गर्नुभयो भने क्यामेरा प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाको हकमा यो अनुमति अनब्लक गरिन्छ।"</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"यसो गर्नुभयो भने क्यामेरा वा माइक्रोफोन प्रयोग गर्ने अनुमति दिइएका सबै एप तथा सेवाको हकमा यो अनुमति अनब्लक गरिन्छ।"</string>
<string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"माइक्रोफोन ब्लक गरिएको छ"</string>
<string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"क्यामेरा ब्लक गरिएको छ"</string>
<string name="sensor_privacy_start_use_mic_camera_blocked_dialog_title" msgid="195236134743281973">"माइक र क्यामेरा ब्लक गरिएको छ"</string>
@@ -932,7 +929,7 @@
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"कुनै स्वचालित नियम वा एपले बाधा नपुऱ्याउनुहोस् नामक विकल्पलाई सक्रिय गऱ्यो।"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"पृष्ठभूमिमा चल्ने एपहरू"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ब्याट्री र डेटाका प्रयोग सम्बन्धी विवरणहरूका लागि ट्याप गर्नुहोस्"</string>
- <string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा निष्क्रिय पार्ने हो?"</string>
+ <string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा अफ गर्ने हो?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"तपाईं <xliff:g id="CARRIER">%s</xliff:g> मार्फत डेटा वा इन्टरनेट प्रयोग गर्न सक्नुहुने छैन। Wi-Fi मार्फत मात्र इन्टरनेट उपलब्ध हुने छ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"तपाईंको सेवा प्रदायक"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"फेरि <xliff:g id="CARRIER">%s</xliff:g> को मोबाइल डेटा अन गर्ने हो?"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड गरिएको"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"अनफोल्ड गरिएको"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"स्टाइलसको ब्याट्री <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"आफ्नो स्टाइलस चार्जरमा कनेक्ट गर्नुहोस्"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"स्टाइलसको ब्याट्री लो छ"</string>
<string name="video_camera" msgid="7654002575156149298">"भिडियो क्यामेरा"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"खोजका सर्टकटहरू"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\"कोल्याप्स गर्नुहोस्\" आइकन"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"\"एक्स्पान्ड गर्नुहोस्\" आइकन"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"वा"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"किबोर्ड ब्याकलाइट"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d मध्ये %1$d औँ स्तर"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"होम कन्ट्रोलहरू"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8cdbf61..3eba8a8 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Morgen weer automatisch aanzetten"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Functies zoals Quick Share en Vind mijn apparaat gebruiken bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth wordt morgenochtend aangezet"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio delen"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio delen…"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batterijniveau"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermisch"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Bediening met 1 hand"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hoortoestellen"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Actief"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Ontkoppeld"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hoortoestellen"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Nieuw apparaat koppelen"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klik om nieuw apparaat te koppelen"</string>
@@ -1324,10 +1324,9 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Snelkoppelingen voor zoekopdrachten"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Icoon voor uitvouwen"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"of"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Achtergrondverlichting van toetsenbord"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d van %2$d"</string>
- <string name="home_controls_dream_label" msgid="6567105701292324257">"Huisbediening"</string>
- <string name="home_controls_dream_description" msgid="4644150952104035789">"Snel toegang tot je huisbediening als screensaver"</string>
+ <string name="home_controls_dream_label" msgid="6567105701292324257">"Bediening voor in huis"</string>
+ <string name="home_controls_dream_description" msgid="4644150952104035789">"Gebruik bediening voor in huis als screensaver"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 287d1a7..1e3ebab 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ଆସନ୍ତାକାଲି ସ୍ୱତଃ ପୁଣି ଚାଲୁ ହେବ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share ଏବଂ Find My Device ପରି ଫିଚରଗୁଡ଼ିକ ବ୍ଲୁଟୁଥ ବ୍ୟବହାର କରେ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ବ୍ଲୁଟୁଥ ଆସନ୍ତା କାଲି ସକାଳେ ଚାଲୁ ହେବ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ଅଡିଓ ସେୟାରିଂ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ଅଡିଓ ସେୟାର କରାଯାଉଛି"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ବ୍ୟାଟେରୀ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ଅଡିଓ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ହେଡସେଟ୍"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ଆପଣଙ୍କ ଡିଭାଇସ ଅନୁଭୂତିର କେଉଁ ଅଂଶ ପ୍ରଭାବିତ ହୋଇଛି?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ସମସ୍ୟାର ପ୍ରକାର ଚୟନ କରନ୍ତୁ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ସ୍କ୍ରିନ ରେକର୍ଡ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ପରଫରମାନ୍ସ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ୟୁଜର ଇଣ୍ଟରଫେସ"</string>
+ <string name="thermal" msgid="6758074791325414831">"ଥର୍ମାଲ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ଏକ-ହାତ ମୋଡ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ସକ୍ରିୟ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ଡିସକନେକ୍ଟ ହୋଇଛି"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ନୂଆ ଡିଭାଇସ ପେୟାର କରନ୍ତୁ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ନୂଆ ଡିଭାଇସ ପେୟାର କରିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"ବ୍ୟାକଗ୍ରାଉଣ୍ଡରେ ଆପ୍ ଚାଲୁଛି"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"ବ୍ୟାଟେରୀ ଏବଂ ଡାଟା ବ୍ୟବହାର ଉପରେ ବିବରଣୀ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ମୋବାଇଲ୍ ଡାଟା ବନ୍ଦ କରିବେ?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"ଡାଟା କିମ୍ବା ଇଣ୍ଟରନେଟ୍କୁ <xliff:g id="CARRIER">%s</xliff:g> ଦ୍ଵାରା ଆପଣଙ୍କର ଆକ୍ସେସ୍ ରହିବ ନାହିଁ। ଇଣ୍ଟରନେଟ୍ କେବଳ ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ ଉପଲବ୍ଧ ହେବ।"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"ଡାଟା କିମ୍ବା ଇଣ୍ଟର୍ନେଟକୁ <xliff:g id="CARRIER">%s</xliff:g> ଦ୍ଵାରା ଆପଣଙ୍କର ଆକ୍ସେସ ରହିବ ନାହିଁ। ଇଣ୍ଟର୍ନେଟ କେବଳ ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ ଉପଲବ୍ଧ ହେବ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ଆପଣଙ୍କ କେରିଅର୍"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"<xliff:g id="CARRIER">%s</xliff:g>କୁ ପୁଣି ସ୍ୱିଚ କରିବେ?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"ଉପଲବ୍ଧତା ଆଧାରରେ ମୋବାଇଲ ଡାଟା ସ୍ୱତଃ ସ୍ୱିଚ ହେବ ନାହିଁ"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{#ଟି ଆପ ସକ୍ରିୟ ଅଛି}other{#ଟି ଆପ ସକ୍ରିୟ ଅଛି}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"ନୂଆ ସୂଚନା"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"ସକ୍ରିୟ ଆପ୍ସ"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"ଆପଣ ଏହି ଆପ୍ସକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ ସେଗୁଡ଼ିକ ସକ୍ରିୟ ରହିଥାଏ ଏବଂ ଚାଲୁଥାଏ। ଏହା ସେଗୁଡ଼ିକର କାର୍ଯ୍ୟକ୍ଷମତାକୁ ଉନ୍ନତ କରେ, କିନ୍ତୁ ଏହା ମଧ୍ୟ ବ୍ୟାଟେରୀ ଲାଇଫକୁ ପ୍ରଭାବିତ କରିପାରେ।"</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"ଆପଣ ଏହି ଆପ୍ସକୁ ବ୍ୟବହାର କରୁନଥିଲେ ମଧ୍ୟ ସେଗୁଡ଼ିକ ସକ୍ରିୟ ରହିଥାଏ ଏବଂ ଚାଲୁଥାଏ। ଏହା ସେଗୁଡ଼ିକର କାର୍ଯ୍ୟକ୍ଷମତାକୁ ଉନ୍ନତ କରେ, କିନ୍ତୁ ଏହା ମଧ୍ୟ ବେଟେରୀ ଲାଇଫକୁ ପ୍ରଭାବିତ କରିପାରେ।"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"ବନ୍ଦ ହୋଇଛି"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"ହୋଇଗଲା"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ଫୋଲ୍ଡେଡ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ଅନଫୋଲ୍ଡେଡ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ଷ୍ଟାଇଲସ ବେଟେରୀ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ଏକ ଚାର୍ଜର ସହ ଆପଣଙ୍କ ଷ୍ଟାଇଲସକୁ କନେକ୍ଟ କରନ୍ତୁ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ଷ୍ଟାଇଲସ ବେଟେରୀର ଚାର୍ଜ କମ ଅଛି"</string>
<string name="video_camera" msgid="7654002575156149298">"ଭିଡିଓ କେମେରା"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ସର୍ଚ୍ଚ ସର୍ଟକଟ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ଆଇକନକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ଆଇକନକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"କିମ୍ବା"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"କୀବୋର୍ଡ ବେକଲାଇଟ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dରୁ %1$d ନମ୍ବର ଲେଭେଲ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ହୋମ କଣ୍ଟ୍ରୋଲ୍ସ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index a16a8a5..dddda72 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"ਕੱਲ੍ਹ ਨੂੰ ਆਪਣੇ ਆਪ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ਕਵਿੱਕ ਸ਼ੇਅਰ ਅਤੇ Find My Device ਵਰਗੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਬਲੂਟੁੱਥ ਵਰਤਦੀਆਂ ਹਨ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"ਬਲੂਟੁੱਥ ਕੱਲ੍ਹ ਸਵੇਰੇ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ਆਡੀਓ ਸਾਂਝਾਕਰਨ"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ਆਡੀਓ ਨੂੰ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ਬੈਟਰੀ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ਆਡੀਓ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ਹੈੱਡਸੈੱਟ"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਿਹੜੀ ਸੁਵਿਧਾ ਪ੍ਰਭਾਵਿਤ ਹੋਈ ਸੀ?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ਸਮੱਸਿਆ ਦੀ ਕਿਸਮ ਚੁਣੋ"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"ਕਾਰਗੁਜ਼ਾਰੀ"</string>
+ <string name="user_interface" msgid="3712869377953950887">"ਯੂਜ਼ਰ ਇੰਟਰਫ਼ੇਸ"</string>
+ <string name="thermal" msgid="6758074791325414831">"ਥਰਮਲ"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ਇੱਕ ਹੱਥ ਮੋਡ"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ਕਿਰਿਆਸ਼ੀਲ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ਡਿਸਕਨੈਕਟ ਹੈ"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"\'ਨਵਾਂ ਡੀਵਾਈਸ ਜੋੜਾਬੱਧ ਕਰੋ\' \'ਤੇ ਕਲਿੱਕ ਕਰੋ"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ਅਣਫੋਲਡਯੋਗ ਡੀਵਾਈਸ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ਆਪਣੇ ਸਟਾਈਲਸ ਨੂੰ ਚਾਰਜਰ ਨਾਲ ਕਨੈਕਟ ਕਰੋ"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ਸਟਾਈਲਸ ਦੀ ਬੈਟਰੀ ਘੱਟ ਹੈ"</string>
<string name="video_camera" msgid="7654002575156149298">"ਵੀਡੀਓ ਕੈਮਰਾ"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ਖੋਜ ਸੰਬੰਧੀ ਸ਼ਾਰਟਕੱਟ"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ਪ੍ਰਤੀਕ ਨੂੰ ਸਮੇਟੋ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ਪ੍ਰਤੀਕ ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ਜਾਂ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ਕੀ-ਬੋਰਡ ਬੈਕਲਾਈਟ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ਵਿੱਚੋਂ %1$d ਪੱਧਰ"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ਹੋਮ ਕੰਟਰੋਲ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 58561f1..2dbcf20 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automatycznie włącz ponownie jutro"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetootha używają funkcje takie jak szybkie udostępnianie czy Znajdź moje urządzenie"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth włączy się jutro rano"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Udostępnianie dźwięku"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Udostępniam dźwięk"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> naładowania baterii"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Dźwięk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Zestaw słuchawkowy"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termografia"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tryb jednej ręki"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Urządzenia słuchowe"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktywny"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Rozłączono"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Urządzenia słuchowe"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sparuj nowe urządzenie"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknij, aby sparować nowe urządzenie"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozwijania"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"lub"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podświetlenie klawiatury"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Poziom %1$d z %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Sterowanie domem"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8f5c519..992db40 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ativar automaticamente de novo amanhã"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Recursos como o Quick Share e o Encontre Meu Dispositivo usam Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth será ativado amanhã de manhã"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartilhamento de áudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartilhando áudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Desempenho"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface do usuário"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ativos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
@@ -639,7 +636,7 @@
<string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
<string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio definido para"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de status"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também afeta a duração da bateria."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria da stylus em <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
<string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index df73572..fb0bbfa 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Reativar amanhã automaticamente"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funcionalidades como a Partilha rápida e o serviço Localizar o meu dispositivo usam o Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth vai ser ativado amanhã de manhã"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Partilha de áudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"A partilhar áudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> de bateria"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ausc. c/ mic. integ."</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo para uma mão"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dispositivos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ativos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desligados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dispositivos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Sincronizar novo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para sincronizar um novo dispositivo"</string>
@@ -930,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Apps em execução em segundo plano"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Desativar os dados móveis?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Não terá acesso a dados ou à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet estará disponível apenas por Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Não vai ter acesso aos dados nem à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet vai estar disponível só por Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"o seu operador"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Mudar de novo para <xliff:g id="CARRIER">%s</xliff:g>?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Os dados móveis não vão mudar automaticamente com base na disponibilidade"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Controlos domésticos"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8f5c519..992db40 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ativar automaticamente de novo amanhã"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Recursos como o Quick Share e o Encontre Meu Dispositivo usam Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"O Bluetooth será ativado amanhã de manhã"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Compartilhamento de áudio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Compartilhando áudio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Áudio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Fone de ouvido"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Que parte da sua experiência no dispositivo foi afetada?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selecionar tipo de problema"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Gravação de tela"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Desempenho"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interface do usuário"</string>
+ <string name="thermal" msgid="6758074791325414831">"Térmico"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modo uma mão"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparelhos auditivos"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Ativos"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Desconectados"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparelhos auditivos"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parear novo dispositivo"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Clique para parear o novo dispositivo"</string>
@@ -639,7 +636,7 @@
<string name="volume_panel_hint_muted" msgid="1124844870181285320">"som desativado"</string>
<string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrar"</string>
<string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string>
- <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string>
+ <string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio definido para"</string>
<string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string>
<string name="status_bar" msgid="4357390266055077437">"Barra de status"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# app está ativo}one{# apps está ativo}many{# de apps estão ativos}other{# apps estão ativos}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"Nova informação"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Apps ativos"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também pode afetar a duração da bateria."</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Esses apps ficam ativos e em execução mesmo quando não estão em uso. Isso melhora a funcionalidade deles, mas também afeta a duração da bateria."</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Parar"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Parado"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"Concluído"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"fechado"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aberto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria da stylus em <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conecte sua stylus a um carregador"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria da stylus fraca"</string>
<string name="video_camera" msgid="7654002575156149298">"Filmadora"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atalhos de pesquisa"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone \"Fechar\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 366480e..ff07fe9 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Activează din nou automat mâine"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funcții precum Quick Share și Găsește-mi dispozitivul folosesc Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se va activa mâine dimineață"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Permiterea accesului la audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Se permite accesul la conținutul audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Căști"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ce parte a experienței pe dispozitiv a fost afectată?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Selectează tipul problemei"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Înregistrarea ecranului"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performanță"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Interfața de utilizare"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modul cu o mână"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Aparate auditive"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Activ"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Deconectat"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Aparate auditive"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Asociază un nou dispozitiv"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Dă clic pentru a asocia un nou dispozitiv"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"închis"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"deschis"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria creionului: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Conectează-ți creionul la un încărcător"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Nivelul bateriei creionului este scăzut"</string>
<string name="video_camera" msgid="7654002575156149298">"Cameră video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Comenzi directe de căutare"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Pictograma de restrângere"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Pictograma de extindere"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"sau"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Iluminarea din spate a tastaturii"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivelul %1$d din %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Comenzi pentru locuință"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index f48e428..1900a8e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Включить завтра автоматически"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth используется в таких функциях и сервисах, как \"Быстрая отправка\" и \"Найти устройство\""</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth включится завтра утром"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Отправка аудио"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Включена отправка аудио"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудиоустройство"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнитура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"С чем связана проблема, с которой вы столкнулись?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Выберите тип проблемы"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запись экрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Производительность"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Интерфейс"</string>
+ <string name="thermal" msgid="6758074791325414831">"Тепловизор"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим управления одной рукой"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слуховые аппараты"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Не подключено"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слуховые аппараты"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Подключить новое устройство"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Нажмите, чтобы подключить новое устройство"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"устройство сложено"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"устройство разложено"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Батарея стилуса: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Поставьте стилус на зарядку."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Низкий заряд батареи стилуса"</string>
<string name="video_camera" msgid="7654002575156149298">"Видеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Найти быстрые клавиши"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок \"Развернуть\""</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка клавиатуры"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Уровень %1$d из %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Управление домом"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 0e621c6..5d41eed 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"හෙට ස්වයංක්රීයව නැවත ක්රියාත්මක කරන්න"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ඉක්මන් බෙදා ගැනීම සහ මගේ උපාංගය සෙවීම වැනි විශේෂාංග බ්ලූටූත් භාවිත කරයි"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"බ්ලූටූත් හෙට උදේ සක්රීය වෙයි"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ශ්රව්ය බෙදා ගැනීම"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ශ්රව්යය බෙදා ගැනීම"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ශ්රව්ය"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"හෙඩ්සෙටය"</string>
@@ -361,24 +363,19 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"ඔබේ උපාංග අත්දැකීමේ කුමන කොටසට බලපෑවේ ද?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"ගැටලු වර්ගය තෝරන්න"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"තිර පටිගත කිරීම"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"කාර්ය සාධනය"</string>
+ <string name="user_interface" msgid="3712869377953950887">"පරිශීලක අතුරු මුහුණත"</string>
+ <string name="thermal" msgid="6758074791325414831">"තාප"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"තනි අත් ප්රකාරය"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ශ්රවණ උපාංග"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ක්රියාකාරී"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"විසන්ධි විය"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ශ්රවණ උපාංග"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"නව උපාංගය යුගල කරන්න"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"නව උපාංගය යුගල කිරීමට ක්ලික් කරන්න"</string>
<string name="hearing_devices_presets_error" msgid="350363093458408536">"පෙර සැකසීම යාවත්කාලීන කළ නොහැකි විය"</string>
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"පෙරසැකසුම"</string>
- <string name="live_caption_title" msgid="8916875614623730005">"සජීවී සිරස්තලය"</string>
+ <string name="live_caption_title" msgid="8916875614623730005">"සජීවී සිරස්තල"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
<string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"උපාංග කැමරාව අවහිර කිරීම ඉවත් කරන්නද?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"උපාංග කැමරාව සහ මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"නැවූ"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"නොනැවූ"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"පන්හිඳ බැටරිය <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"ඔබේ පන්හිඳ චාජරයකට සම්බන්ධ කරන්න"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"පන්හිඳ බැටරිය අඩුයි"</string>
<string name="video_camera" msgid="7654002575156149298">"වීඩියෝ කැමරාව"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"කෙටි මං සොයන්න"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"හැකුළුම් නිරූපකය"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"දිගහැරීම් නිරූපකය"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"හෝ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"යතුරු පුවරු පසු ආලෝකය"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dන් %1$d වැනි මට්ටම"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"නිවෙස් පාලන"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ba72fb4..eef2a01 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Automaticky zajtra znova zapnúť"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcie ako Quick Share a Nájdi moje zariadenie používajú Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sa zapne zajtra ráno"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Zdieľanie zvuku"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Zdieľa sa zvuk"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batéria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvuk"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Náhlavná súprava"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Čo v zariadení bolo ovplyvnené?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Vyberte typ problému"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekordér obrazovky"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Výkon"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Používateľské rozhranie"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termálne"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Režim jednej ruky"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Načúvacie zariadenia"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktívne"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Odpojené"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Načúvacie zariadenia"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovať nové zariadenie"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zariadenie"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zložené"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batéria dotykového pera: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Pripojte dotykové pero k nabíjačke"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Stav batérie dotykového pera je nízky"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,10 +1324,9 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Vyhľadávacie odkazy"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona rozbalenia"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"alebo"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládanie domácnosti"</string>
- <string name="home_controls_dream_description" msgid="4644150952104035789">"Rýchlejšie ovládanie domácnosti v šetriči obrazov."</string>
+ <string name="home_controls_dream_description" msgid="4644150952104035789">"Rýchly prístup k ovládaniu domácnosti z šetriča obrazovky"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index c6c1439..facf72b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Samodejno znova vklopi jutri"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkcije, kot sta Hitro deljenje in Poišči mojo napravo, uporabljajo Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se bo vklopil jutri zjutraj"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Deljenje zvoka"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Poteka deljenje zvoka"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterija na <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Zvok"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Slušalke z mikrofonom"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Na kateri del izkušnje z napravo je to vplivalo?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Izberite vrsto težave"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Snemanje zaslona"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Učinkovitost delovanja"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Uporabniški vmesnik"</string>
+ <string name="thermal" msgid="6758074791325414831">"Toplotno"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enoročni način"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušni pripomočki"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktivno"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Brez povezave"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni pripomočki"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Seznanitev nove naprave"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite za seznanitev nove naprave"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zaprto"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"razprto"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Napolnjenost baterije pisala: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Povežite pisalo s polnilnikom."</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Skoraj prazna baterija pisala"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Bližnjice za iskanje"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ali"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Osvetlitev tipkovnice"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Stopnja %1$d od %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrolniki za dom"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index dc9407f..5333632 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktivizoje automatikisht sërish nesër"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Veçoritë e tilla si \"Ndarja e shpejtë\" dhe \"Gjej pajisjen time\" përdorin Bluetooth-in"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth-i do të aktivizohet nesër në mëngjes"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ndarja e audios"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audioja po ndahet"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> bateri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Kufje me mikrofon"</string>
@@ -361,12 +363,9 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cila pjesë e përvojës me pajisjen është prekur?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Zgjidh llojin e problemit"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Regjistrim i ekranit"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performanca"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Ndërfaqja e përdoruesit"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termike"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modaliteti i përdorimit me një dorë"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Pajisje ndihmëse për dëgjimin"</string>
<!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
@@ -1275,8 +1274,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"palosur"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"shpalosur"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Bateria e stilolapsit: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Lidhe stilolapsin me një karikues"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bateria e stilolapsit në nivel të ulët"</string>
<string name="video_camera" msgid="7654002575156149298">"Videokamera"</string>
@@ -1328,8 +1326,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Kërko për shkurtoret"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona e palosjes"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona e zgjerimit"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ose"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Drita e sfondit e tastierës"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveli: %1$d nga %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrollet e shtëpisë"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1228eef..f35d7d8 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Аутоматски поново укључи сутра"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Функције као што су Quick Share и Пронађи мој уређај користе Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ће се укључити сутра ујутру"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Дељење звука"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Дели се звук"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Ниво батерије је <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудио"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Слушалице"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Термална камера"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим једном руком"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слушни апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Активно"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Веза је прекинута"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слушни апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Упари нови уређај"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Кликните да бисте упарили нов уређај"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пречице претраге"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Икона за проширивање"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"или"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Позадинско осветљење тастатуре"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. ниво од %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Контроле за дом"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index cf2b93c..535a4aa 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Aktivera automatiskt igen i morgon"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funktioner som Snabbdelning och Hitta min enhet använder Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth aktiveras i morgon bitti"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ljuddelning"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Delar ljud"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> batteri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ljud"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termisk"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Enhandsläge"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Hörhjälpmedel"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktiva"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Frånkopplade"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Hörhjälpmedel"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Parkoppla en ny enhet"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Klicka för att parkoppla en ny enhet"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sökgenvägar"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikonen Komprimera"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrundsbelysning för tangentbord"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Hemstyrning"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1ee1d0c..98a7e03 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Iwashe tena kesho kiotomatiki"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Vipengele kama vile Kutuma Haraka na Tafuta Kifaa Changu hutumia Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth itawaka kesho asubuhi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Kusikiliza Pamoja"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Mnasikiliza Pamoja"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Chaji ya betri ni <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Sauti"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Vifaa vya sauti"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Ni sehemu gani ya matumizi ya kifaa iliathiriwa?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chagua aina ya tatizo"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Rekodi ya skrini"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Utendaji"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kiolesura"</string>
+ <string name="thermal" msgid="6758074791325414831">"Joto"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Hali ya kutumia kwa mkono mmoja"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Vifaa vya kusikilizia"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Vimeunganishwa"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Havijaunganishwa"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Vifaa vya kusikilizia"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Unganisha kifaa kipya"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Bofya ili uunganishe kifaa kipya"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kimekunjwa"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kimefunguliwa"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Betri ya stylus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Unganisha stylus yako kwenye chaja"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Chaji ya betri ya Stylus imepungua"</string>
<string name="video_camera" msgid="7654002575156149298">"Kamera ya video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Njia mkato za kutafutia"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kunja aikoni"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Panua aikoni"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"au"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Mwanga chini ya kibodi"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Kiwango cha %1$d kati ya %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Dhibiti Vifaa Nyumbani"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6e95c3b..896b55f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"நாளைக்குத் தானாகவே மீண்டும் இயக்கப்படுதல்"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"விரைவுப் பகிர்தல், Find My Device போன்ற அம்சங்கள் புளூடூத்தைப் பயன்படுத்துகின்றன"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"நாளை காலை புளூடூத் இயக்கப்படும்"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ஆடியோ பகிர்வு"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ஆடியோ பகிரப்படுகிறது"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> பேட்டரி"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ஆடியோ"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ஹெட்செட்"</string>
@@ -305,7 +307,7 @@
<string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"நெட்வொர்க்குகள் கிடைக்கவில்லை"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"வைஃபை நெட்வொர்க்குகள் இல்லை"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"ஆன் செய்கிறது…"</string>
- <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string>
+ <string name="quick_settings_cast_title" msgid="3033553249449938182">"அலைபரப்பு"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"அனுப்புகிறது"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"பெயரிடப்படாத சாதனம்"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"சாதனங்கள் இல்லை"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"சாதன அனுபவத்தின் எந்தப் பகுதி பாதிக்கப்பட்டது?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"சிக்கல் வகையைத் தேர்வுசெய்க"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"ஸ்கிரீன் ரெக்கார்டு"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"செயல்திறன்"</string>
+ <string name="user_interface" msgid="3712869377953950887">"பயனர் இடைமுகம்"</string>
+ <string name="thermal" msgid="6758074791325414831">"தெர்மல்"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ஒற்றைக் கைப் பயன்முறை"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"செவித்துணைக் கருவிகள்"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"செயலில் உள்ளது"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"இணைக்கப்படவில்லை"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"செவித்துணைக் கருவிகள்"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"புதிய சாதனத்தை இணை"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"புதிய சாதனத்தை இணைக்க கிளிக் செய்யலாம்"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"மடக்கப்பட்டது"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"விரிக்கப்பட்டது"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"ஸ்டைலஸ் பேட்டரி <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"உங்கள் ஸ்டைலஸைச் சார்ஜருடன் இணையுங்கள்"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"ஸ்டைலஸின் பேட்டரி குறைவாக உள்ளது"</string>
<string name="video_camera" msgid="7654002575156149298">"வீடியோ கேமரா"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"தேடல் ஷார்ட்கட்கள்"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"சுருக்குவதற்கான ஐகான்"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"விரிவாக்குவதற்கான ஐகான்"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"அல்லது"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"கீபோர்டு பேக்லைட்"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"நிலை, %2$d இல் %1$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ஹோம் கன்ட்ரோல்கள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 64d6f9e..b88386f 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"రేపు మళ్లీ ఆటోమేటిక్గా ఆన్ చేస్తుంది"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"క్విక్ షేర్, Find My Device వంటి ఫీచర్లు బ్లూటూత్ను ఉపయోగిస్తాయి"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"బ్లూటూత్ రేపు ఉదయం ఆన్ అవుతుంది"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ఆడియో షేరింగ్"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"ఆడియోను షేర్ చేస్తున్నారు"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> బ్యాటరీ"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"ఆడియో"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"హెడ్సెట్"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"మీ పరికర అనుభవంలో ఏ భాగం ప్రభావితమైంది?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"సమస్య రకాన్ని ఎంచుకోండి"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"స్క్రీన్ రికార్డ్"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"పనితీరు"</string>
+ <string name="user_interface" msgid="3712869377953950887">"యూజర్ ఇంటర్ఫేస్"</string>
+ <string name="thermal" msgid="6758074791325414831">"థర్మల్"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"వన్-హ్యాండెడ్ మోడ్"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"వినికిడి పరికరాలు"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"యాక్టివ్"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"డిస్కనెక్ట్ అయ్యింది"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"వినికిడి పరికరాలు"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"కొత్త పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"కొత్త పరికరాన్ని పెయిర్ చేయడానికి క్లిక్ చేయండి"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"మడిచే సదుపాయం గల పరికరం"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"మడిచే సదుపాయం లేని పరికరం"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"స్టయిలస్ బ్యాటరీ <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"మీ స్టైలస్ను ఛార్జర్కి కనెక్ట్ చేయండి"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"తక్కువ స్టైలస్ బ్యాటరీ"</string>
<string name="video_camera" msgid="7654002575156149298">"వీడియో కెమెరా"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"సెర్చ్ షార్ట్కట్లు"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"విస్తరించండి చిహ్నం"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"లేదా"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"కీబోర్డ్ బ్యాక్లైట్"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dలో %1$dవ స్థాయి"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"హోమ్ కంట్రోల్స్"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 8a76629..12c676e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -279,10 +279,12 @@
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"ยกเลิกการเชื่อมต่อ"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"เปิดใช้งาน"</string>
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"เปิดอีกครั้งโดยอัตโนมัติในวันพรุ่งนี้"</string>
- <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ฟีเจอร์ต่างๆ เช่น Quick Share และหาอุปกรณ์ของฉัน ใช้บลูทูธ"</string>
+ <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"ฟีเจอร์ต่างๆ เช่น Quick Share และ \"หาอุปกรณ์ของฉัน\" ใช้บลูทูธ"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"บลูทูธจะเปิดพรุ่งนี้เช้า"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"การแชร์เสียง"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"กำลังแชร์เสียง"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"เสียง"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ชุดหูฟัง"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"ความร้อน"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"โหมดมือเดียว"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"เครื่องช่วยฟัง"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"ใช้งานอยู่"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"ยกเลิกการเชื่อมต่อแล้ว"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"เครื่องช่วยฟัง"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"จับคู่อุปกรณ์ใหม่"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"คลิกเพื่อจับคู่อุปกรณ์ใหม่"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ค้นหาแป้นพิมพ์ลัด"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ไอคอนขยาย"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"หรือ"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ไฟแบ็กไลต์ของแป้นพิมพ์"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"ระดับที่ %1$d จาก %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ระบบควบคุมอุปกรณ์สมาร์ทโฮม"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index e74139f..84a4541 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Awtomatikong i-on ulit bukas"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Gumagamit ng Bluetooth ang mga feature tulad ng Quick Share at Hanapin ang Aking Device"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Mag-o-on ang Bluetooth bukas ng umaga"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Pag-share ng Audio"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ibinabahagi ang Audio"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> na baterya"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Headset"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Thermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"One-hand mode"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Mga hearing device"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Aktibo"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Nadiskonekta"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Mga hearing device"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Magpares ng bagong device"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"I-click para magpares ng bagong device"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"I-expand ang icon"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"o"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Backlight ng keyboard"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d sa %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Mga Home Control"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a66fbed..c2df2c2 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Yarın otomatik olarak tekrar aç"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Quick Share ve Cihazımı Bul gibi özellikler Bluetooth\'u kullanır"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth yarın sabah açılacak"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ses Paylaşımı"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ses paylaşılıyor"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Pil düzeyi <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Ses"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Mikrofonlu kulaklık"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Cihaz deneyiminiz ne şekilde etkilendi?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Sorun türünü seçin"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ekran kaydedicisi"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Performans"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Kullanıcı Arayüzü"</string>
+ <string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Tek el modu"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"İşitme cihazları"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Etkin"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Bağlı değil"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"İşitme cihazları"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yeni cihaz eşle"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yeni cihaz eşlemek için tıklayın"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"katlanmış"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"katlanmamış"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Ekran kalemi pili: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Ekran kaleminizi bir şarj cihazına bağlayın"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ekran kaleminin pil seviyesi düşük"</string>
<string name="video_camera" msgid="7654002575156149298">"Video kamera"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Arama kısayolları"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Daralt simgesi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Genişlet simgesi"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"veya"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klavye aydınlatması"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Seviye %1$d / %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Ev Kontrolleri"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5262d74..5fcfb3e 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Автоматично ввімкнути знову завтра"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Такі функції, як швидкий обмін і \"Знайти пристрій\", використовують Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth увімкнеться завтра вранці"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Надсилання аудіо"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Надсилання аудіо"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> заряду акумулятора"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Аудіопристрій"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Гарнітура"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"На який аспект роботи пристрою вплинула проблема?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Виберіть тип проблеми"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Запис відео з екрана"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Продуктивність"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Інтерфейс користувача"</string>
+ <string name="thermal" msgid="6758074791325414831">"Нагрівання"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Режим керування однією рукою"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Слухові апарати"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Під’єднано"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Від’єднано"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухові апарати"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Підключити новий пристрій"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Натисніть, щоб підключити новий пристрій"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складений"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"розкладений"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Заряд акумулятора стилуса: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Підключіть стилус до зарядного пристрою"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Низький заряд акумулятора стилуса"</string>
<string name="video_camera" msgid="7654002575156149298">"Відеокамера"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Комбінації клавіш для пошуку"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок згортання"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Значок розгортання"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"або"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Підсвічування клавіатури"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Рівень %1$d з %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Автоматизація дому"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0d3f1fe..f08dd7e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -278,11 +278,13 @@
<string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"محفوظ ہے"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"غیر منسلک کریں"</string>
<string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"فعال کریں"</string>
- <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"کل دوبارہ خودکار طور پر آن ہوگا"</string>
+ <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"کل دوبارہ خودکار طور پر آن کریں"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"فوری اشتراک اور \'میرا آلہ ڈھونڈیں\' جیسی خصوصیات بلوٹوتھ کا استعمال کرتی ہیں"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"بلوٹوتھ کل صبح آن ہو جائے گا"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"آڈیو کا اشتراک"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"آڈیو کا اشتراک ہو رہا ہے"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> بیٹری"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"آڈیو"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"ہیڈ سیٹ"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"تھرمل"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"ایک ہاتھ کی وضع"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"سماعت کے آلات"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"فعال"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"غیر منسلک ہے"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"سماعت کے آلات"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"نئے آلے کا جوڑا بنائیں"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"نئے آلے کا جوڑا بنانے کے لیے کلک کریں"</string>
@@ -1328,8 +1328,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"تلاش کے شارٹ کٹس"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"آئیکن پھیلائیں"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"یا"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"کی بورڈ بیک لائٹ"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d میں سے %1$d کا لیول"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"ہوم کنٹرولز"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 3f3983d..4a04a33 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Ertaga yana avtomatik yoqilsin"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Tezkor ulashuv va Qurilmamni top kabi funksiyalar Bluetooth ishlatadi"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth ertaga ertalab yoqiladi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Audio ulashuvi"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Audio ulashuvi yoniq"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Batareya quvvati: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audio"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Garnitura"</string>
@@ -366,10 +368,8 @@
<string name="thermal" msgid="6758074791325414831">"Termal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Ixcham rejim"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Eshitish qurilmalari"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Faol"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Uzildi"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Eshitish qurilmalari"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Yangi qurilmani ulash"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Yangi qurilmani ulash uchun bosing"</string>
@@ -1324,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"yoki"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura orqa yoritkichi"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Daraja: %1$d / %2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Uy boshqaruvi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index dc4fa12..45d9165 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Tự động bật lại vào ngày mai"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Các tính năng như Chia sẻ nhanh và Tìm thiết bị của tôi đều sử dụng Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth sẽ bật vào sáng mai"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Chia sẻ âm thanh"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Đang chia sẻ âm thanh"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> pin"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Âm thanh"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Tai nghe"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Bạn gặp loại vấn đề gì khi dùng thiết bị?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Chọn loại vấn đề"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Ghi màn hình"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Hiệu suất"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Giao diện người dùng"</string>
+ <string name="thermal" msgid="6758074791325414831">"Nhiệt"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Chế độ một tay"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Thiết bị trợ thính"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Đang hoạt động"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Đã ngắt kết nối"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Thiết bị trợ thính"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Ghép nối thiết bị mới"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Nhấp để ghép nối thiết bị mới"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"Ứng dụng đang chạy trong nền"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"Nhấn để biết chi tiết về mức sử dụng dữ liệu và pin"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Tắt dữ liệu di động?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"Bạn sẽ không có quyền sử dụng dữ liệu hoặc truy cập Internet thông qua chế độ <xliff:g id="CARRIER">%s</xliff:g>. Bạn chỉ có thể truy cập Internet thông qua Wi-Fi."</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"Bạn sẽ không có quyền sử dụng dữ liệu hoặc truy cập Internet thông qua mạng <xliff:g id="CARRIER">%s</xliff:g>. Bạn chỉ có thể truy cập Internet thông qua Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"nhà mạng của bạn"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Chuyển về <xliff:g id="CARRIER">%s</xliff:g>?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Dữ liệu di động sẽ không tự động chuyển dựa trên tình trạng phủ sóng"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gập"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"mở"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Mức pin bút cảm ứng <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Hãy kết nối bút cảm ứng với bộ sạc"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Bút cảm ứng bị yếu pin"</string>
<string name="video_camera" msgid="7654002575156149298">"Máy quay video"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Lối tắt tìm kiếm"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Biểu tượng Thu gọn"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Biểu tượng Mở rộng"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"hoặc"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Đèn nền bàn phím"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Độ sáng %1$d/%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Điều khiển nhà"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 9b69f9e..98a1187 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明天自动重新开启"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"快速分享、查找我的设备等功能会使用蓝牙"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"蓝牙将在明天早上开启"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音频分享"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"正在分享音频"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> 的电量"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音频"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳机"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"设备体验的哪个方面受到影响?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"选择问题类型"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"屏幕录制"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"性能"</string>
+ <string name="user_interface" msgid="3712869377953950887">"界面"</string>
+ <string name="thermal" msgid="6758074791325414831">"散热"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"单手模式"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助听装置"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"已连接"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"已断开连接"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助听装置"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"与新设备配对"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"点击即可与新设备配对"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折叠状态"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"展开状态"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"触控笔电量为 <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"请将触控笔连接充电器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"触控笔电池电量低"</string>
<string name="video_camera" msgid="7654002575156149298">"摄像机"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜索快捷键"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展开图标"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"键盘背光"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 级,共 %2$d 级"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"家居控制"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5c164ab..edc624f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明天自動重新開啟"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"「快速共享」和「尋找我的裝置」等功能都會使用藍牙"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"藍牙將於明天上午開啟"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音訊分享功能"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"正在分享音訊"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受影響?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"效能"</string>
+ <string name="user_interface" msgid="3712869377953950887">"使用者介面"</string>
+ <string name="thermal" msgid="6758074791325414831">"熱能"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"已連線"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"已中斷連線"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"㩒一下就可以配對新裝置"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已打開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"觸控筆電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆連接充電器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電量不足"</string>
<string name="video_camera" msgid="7654002575156149298">"攝影機"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"智能家居"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 0d50ad5..5679282 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明天自動重新開啟"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"「快速分享」和「尋找我的裝置」等功能都需要使用藍牙技術"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"藍牙會在明天早上開啟"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"音訊分享"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"正在分享音訊"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"音訊"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"耳機"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"哪些裝置使用體驗受到影響?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"選取問題類型"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"螢幕錄影"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"效能"</string>
+ <string name="user_interface" msgid="3712869377953950887">"使用者介面"</string>
+ <string name="thermal" msgid="6758074791325414831">"熱成像"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"單手模式"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"助聽器"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"已連線"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"連線中斷"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"助聽器"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"配對新裝置"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"按一下即可配對新裝置"</string>
@@ -380,7 +377,7 @@
<string name="hearing_devices_preset_label" msgid="7878267405046232358">"預設"</string>
<string name="live_caption_title" msgid="8916875614623730005">"即時字幕"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>
- <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"要解除封鎖裝置相機嗎?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"解除封鎖裝置相機?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"要將裝置的相機和麥克風解除封鎖嗎?"</string>
<string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"執行後,具備麥克風存取權的所有應用程式和服務,都將可使用麥克風。"</string>
<string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"執行後,具備相機存取權的所有應用程式和服務,都將可使用相機。"</string>
@@ -933,7 +930,7 @@
<string name="running_foreground_services_title" msgid="5137313173431186685">"在背景執行的應用程式"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"輕觸即可查看電池和數據用量詳情"</string>
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要關閉行動數據嗎?"</string>
- <string name="mobile_data_disable_message" msgid="8604966027899770415">"你將無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用行動數據或網際網路。你只能透過 Wi-Fi 使用網際網路。"</string>
+ <string name="mobile_data_disable_message" msgid="8604966027899770415">"你將無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用行動數據或網際網路,只能利用 Wi-Fi 上網。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"你的電信業者"</string>
<string name="auto_data_switch_disable_title" msgid="5146527155665190652">"要切換回「<xliff:g id="CARRIER">%s</xliff:g>」嗎?"</string>
<string name="auto_data_switch_disable_message" msgid="5885533647399535852">"行動數據不會依據可用性自動切換"</string>
@@ -1210,7 +1207,7 @@
<string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# 個應用程式正在運作}other{# 個應用程式正在運作}}"</string>
<string name="fgs_dot_content_description" msgid="2865071539464777240">"新資訊"</string>
<string name="fgs_manager_dialog_title" msgid="5879184257257718677">"運作中的應用程式"</string>
- <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"這些應用程式會在沒有使用的情況下持續運作。應用程式的實用度會因此提升,但也可能影響電池續航力。"</string>
+ <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"這些應用程式即使是在閒置狀態下,也會持續運作。應用程式的功能會因而提升,但也可能影響電池續航力。"</string>
<string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"停止"</string>
<string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"已停止"</string>
<string name="clipboard_edit_text_done" msgid="4551887727694022409">"完成"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已展開"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"觸控筆電量:<xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"將觸控筆接上充電器"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"觸控筆電力不足"</string>
<string name="video_camera" msgid="7654002575156149298">"攝影機"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜尋快速鍵"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收合圖示"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"展開圖示"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"或"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"居家控制"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2e03bd5..a0a57ac 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -281,8 +281,10 @@
<string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Vula ngokuzenzekela futhi kusasa"</string>
<string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Izakhi ezifana nokuthi Ukwabelana Ngokushesha kanye nokuthi Thola Idivayisi Yami zisebenzisa i-Bluetooth"</string>
<string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"IBluetooth izovuleka kusasa ekuseni"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Ukwabelana Ngokuqoshiwe"</string>
- <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Ukwabelana Ngomsindo"</string>
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button (7545274861795853838) -->
+ <skip />
+ <!-- no translation found for quick_settings_bluetooth_audio_sharing_button_sharing (3069309588231072128) -->
+ <skip />
<string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g> ibhethri"</string>
<string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Umsindo"</string>
<string name="quick_settings_bluetooth_secondary_label_headset" msgid="2332093067553000852">"Ihedisethi"</string>
@@ -361,18 +363,13 @@
<string name="qs_record_issue_dropdown_header" msgid="5995983175678658329">"Kuthinteke yiphi ingxenye yokusebenzisa idivayisi?"</string>
<string name="qs_record_issue_dropdown_prompt" msgid="2526949919167046219">"Khetha uhlobo lwenkinga"</string>
<string name="qs_record_issue_dropdown_screenrecord" msgid="6396141928484257626">"Irekhodi lesikrini"</string>
- <!-- no translation found for performance (6552785217174378320) -->
- <skip />
- <!-- no translation found for user_interface (3712869377953950887) -->
- <skip />
- <!-- no translation found for thermal (6758074791325414831) -->
- <skip />
+ <string name="performance" msgid="6552785217174378320">"Ukusebenza"</string>
+ <string name="user_interface" msgid="3712869377953950887">"Okusetshenziswa Kubonwa"</string>
+ <string name="thermal" msgid="6758074791325414831">"Ithermal"</string>
<string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Imodi yesandla esisodwa"</string>
<string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Izinsizakuzwa"</string>
- <!-- no translation found for quick_settings_hearing_devices_connected (6519069502397037781) -->
- <skip />
- <!-- no translation found for quick_settings_hearing_devices_disconnected (8907061223998176187) -->
- <skip />
+ <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Kuyasebenza"</string>
+ <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Inqamukile"</string>
<string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Izinsizakuzwa"</string>
<string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Bhangqa idivayisi entsha"</string>
<string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Chofoza ukuze ubhangqe idivayisi entsha"</string>
@@ -1275,8 +1272,7 @@
<string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kugoqiwe"</string>
<string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kuvuliwe"</string>
<string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string>
- <!-- no translation found for stylus_battery_low_percentage (2564243323894629626) -->
- <skip />
+ <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Ibhethri lestylus <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Xhuma i-stylus yakho kushaja"</string>
<string name="stylus_battery_low" msgid="7134370101603167096">"Ibhethri le-stylus liphansi"</string>
<string name="video_camera" msgid="7654002575156149298">"Ikhamera yevidiyo"</string>
@@ -1328,8 +1324,7 @@
<string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sesha izinqamuleli"</string>
<string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Goqa isithonjana"</string>
<string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Nweba isithonjana"</string>
- <!-- no translation found for shortcut_helper_key_combinations_or_separator (7082902112102125540) -->
- <skip />
+ <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"noma"</string>
<string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Ilambu lekhibhodi"</string>
<string name="keyboard_backlight_value" msgid="7336398765584393538">"Ileveli %1$d ka-%2$d"</string>
<string name="home_controls_dream_label" msgid="6567105701292324257">"Izilawuli Zasekhaya"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0017db6..fe968a7 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -319,6 +319,29 @@
<string name="screenrecord_save_error">Error saving screen recording</string>
<!-- 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>
+ <!-- Title for a dialog shown to the user that will let them stop recording their screen [CHAR LIMIT=50] -->
+ <string name="screenrecord_stop_dialog_title">Stop recording screen?</string>
+ <!-- Text telling a user that they will stop recording their screen if they click the "Stop recording" button [CHAR LIMIT=100] -->
+ <string name="screenrecord_stop_dialog_message">You will stop recording your screen</string>
+ <!-- Button to stop a screen recording [CHAR LIMIT=35] -->
+ <string name="screenrecord_stop_dialog_button">Stop recording</string>
+
+ <!-- Title for a dialog shown to the user that will let them stop sharing their screen to another app on the device [CHAR LIMIT=50] -->
+ <string name="share_to_app_stop_dialog_title">Stop sharing screen?</string>
+ <!-- Text telling a user that they will stop sharing their screen if they click the "Stop sharing" button [CHAR LIMIT=100] -->
+ <string name="share_to_app_stop_dialog_message">You will stop sharing your screen</string>
+ <!-- Button to stop screen sharing [CHAR LIMIT=35] -->
+ <string name="share_to_app_stop_dialog_button">Stop sharing</string>
+
+ <!-- Title for a dialog shown to the user that will let them stop casting their screen to a different device [CHAR LIMIT=50] -->
+ <string name="cast_to_other_device_stop_dialog_title">Stop casting screen?</string>
+ <!-- Text telling a user that they will stop casting their screen to a different device if they click the "Stop casting" button [CHAR LIMIT=100] -->
+ <string name="cast_to_other_device_stop_dialog_message">You will stop casting your screen</string>
+ <!-- Button to stop screen casting to a different device [CHAR LIMIT=35] -->
+ <string name="cast_to_other_device_stop_dialog_button">Stop casting</string>
+
+ <!-- Button to close a dialog without doing any action [CHAR LIMIT=20] -->
+ <string name="close_dialog_button">Close</string>
<!-- Notification title displayed for issue recording [CHAR LIMIT=50]-->
<string name="issuerecord_title">Issue Recorder</string>
@@ -3538,6 +3561,15 @@
-->
<string name="shortcut_helper_key_combinations_or_separator">or</string>
+ <!-- Label for button opening tutorial for back gesture on touchpad [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_back_gesture_button">Back gesture</string>
+ <!-- Label for button opening tutorial for back gesture on touchpad [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_home_gesture_button">Home gesture</string>
+ <!-- Label for button opening tutorial on using Action key from keyboard [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_action_key_button">Action key</string>
+ <!-- Label for button finishing touchpad tutorial [CHAR LIMIT=NONE] -->
+ <string name="touchpad_tutorial_done_button">Done</string>
+
<!-- Content description for keyboard backlight brightness dialog [CHAR LIMIT=NONE] -->
<string name="keyboard_backlight_dialog_title">Keyboard backlight</string>
<!-- Content description for keyboard backlight brightness value [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
index 7a8c82c..4fd5456 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
@@ -37,10 +37,17 @@
private lateinit var rootView: ViewGroup
private var translationMax = 0f
+ /**
+ * Initializes the animator, it is allowed to call this method multiple times, for example
+ * to update the rootView or maximum translation
+ */
fun init(rootView: ViewGroup, translationMax: Float) {
+ if (!::rootView.isInitialized) {
+ progressProvider.addCallback(this)
+ }
+
this.rootView = rootView
this.translationMax = translationMax
- progressProvider.addCallback(this)
}
override fun onTransitionStarted() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index 7170be61..19d918f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -17,16 +17,21 @@
package com.android.keyguard
import android.content.Context
-import android.view.ViewGroup
-import com.android.systemui.res.R
+import android.view.View
+import com.android.systemui.keyguard.MigrateClocksToBlueprint
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.StatusBarState.KEYGUARD
+import com.android.systemui.res.R
+import com.android.systemui.shared.R as sharedR
+import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.END
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.START
import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
+import com.android.systemui.statusbar.StatusBarState.KEYGUARD
import com.android.systemui.unfold.SysUIUnfoldScope
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.dagger.NaturalRotation
import javax.inject.Inject
/**
@@ -38,8 +43,10 @@
@Inject
constructor(
private val context: Context,
+ private val keyguardRootView: KeyguardRootView,
+ private val shadeWindowView: NotificationShadeWindowView,
statusBarStateController: StatusBarStateController,
- unfoldProgressProvider: NaturalRotationUnfoldProgressProvider,
+ @NaturalRotation unfoldProgressProvider: UnfoldTransitionProgressProvider,
) {
/** Certain views only need to move if they are not currently centered */
@@ -50,27 +57,94 @@
private val filterKeyguard: () -> Boolean = { statusBarStateController.getState() == KEYGUARD }
private val translateAnimator by lazy {
+ val smartSpaceViews = if (MigrateClocksToBlueprint.isEnabled) {
+ // Use scrollX instead of translationX as translation is already set by [AodBurnInLayer]
+ val scrollXTranslation = { view: View, translation: Float ->
+ view.scrollX = -translation.toInt()
+ }
+
+ setOf(
+ ViewIdToTranslate(
+ viewId = sharedR.id.date_smartspace_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = scrollXTranslation,
+ ),
+ ViewIdToTranslate(
+ viewId = sharedR.id.bc_smartspace_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = scrollXTranslation,
+ ),
+ ViewIdToTranslate(
+ viewId = sharedR.id.weather_smartspace_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = scrollXTranslation,
+ )
+ )
+ } else {
+ setOf(ViewIdToTranslate(
+ viewId = R.id.keyguard_status_area,
+ direction = START,
+ shouldBeAnimated = filterKeyguard,
+ translateFunc = { view, value ->
+ (view as? KeyguardStatusAreaView)?.translateXFromUnfold = value
+ }
+ ))
+ }
+
UnfoldConstantTranslateAnimator(
viewsIdToTranslate =
setOf(
- ViewIdToTranslate(R.id.keyguard_status_area, START, filterKeyguard,
- { view, value ->
- (view as? KeyguardStatusAreaView)?.translateXFromUnfold = value
- }),
ViewIdToTranslate(
- R.id.lockscreen_clock_view_large, START, filterKeyguardAndSplitShadeOnly),
- ViewIdToTranslate(R.id.lockscreen_clock_view, START, filterKeyguard),
+ viewId = R.id.lockscreen_clock_view_large,
+ direction = START,
+ shouldBeAnimated = filterKeyguardAndSplitShadeOnly
+ ),
ViewIdToTranslate(
- R.id.notification_stack_scroller, END, filterKeyguardAndSplitShadeOnly),
- ViewIdToTranslate(R.id.start_button, START, filterKeyguard),
- ViewIdToTranslate(R.id.end_button, END, filterKeyguard)),
- progressProvider = unfoldProgressProvider)
+ viewId = R.id.lockscreen_clock_view,
+ direction = START,
+ shouldBeAnimated = filterKeyguard
+ ),
+ ViewIdToTranslate(
+ viewId = R.id.notification_stack_scroller,
+ direction = END,
+ shouldBeAnimated = filterKeyguardAndSplitShadeOnly
+ )
+ ) + smartSpaceViews,
+ progressProvider = unfoldProgressProvider
+ )
}
- /** Relies on the [parent] to locate views to translate. */
- fun setup(parent: ViewGroup) {
+ private val shortcutButtonsAnimator by lazy {
+ UnfoldConstantTranslateAnimator(
+ viewsIdToTranslate =
+ setOf(
+ ViewIdToTranslate(
+ viewId = R.id.start_button,
+ direction = START,
+ shouldBeAnimated = filterKeyguard
+ ),
+ ViewIdToTranslate(
+ viewId = R.id.end_button,
+ direction = END,
+ shouldBeAnimated = filterKeyguard
+ )
+ ),
+ progressProvider = unfoldProgressProvider
+ )
+ }
+
+ /** Initializes the keyguard fold/unfold transition */
+ fun setup() {
val translationMax =
context.resources.getDimensionPixelSize(R.dimen.keyguard_unfold_translation_x).toFloat()
- translateAnimator.init(parent, translationMax)
+
+ translateAnimator.init(shadeWindowView, translationMax)
+
+ // Use keyguard root view as there is another instance of start/end buttons with the same ID
+ // outside of the keyguard root view
+ shortcutButtonsAnimator.init(keyguardRootView, translationMax)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
index a242d5a..abdc333 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/ambient/statusbar/ui/AmbientStatusBarViewController.java
@@ -30,6 +30,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamLogger;
import com.android.systemui.dreams.DreamOverlayNotificationCountProvider;
@@ -82,9 +83,11 @@
private final Executor mMainExecutor;
private final List<DreamOverlayStatusBarItemsProvider.StatusBarItem> mExtraStatusBarItems =
new ArrayList<>();
+ private final CommunalSceneInteractor mCommunalSceneInteractor;
private final DreamLogger mLogger;
private boolean mIsAttached;
+ private boolean mCommunalVisible;
// Whether dream entry animations are finished.
private boolean mEntryAnimationsFinished = false;
@@ -140,6 +143,7 @@
DreamOverlayStateController dreamOverlayStateController,
UserTracker userTracker,
WifiInteractor wifiInteractor,
+ CommunalSceneInteractor communalSceneInteractor,
@DreamLog LogBuffer logBuffer) {
super(view);
mResources = resources;
@@ -155,6 +159,7 @@
mDreamOverlayStateController = dreamOverlayStateController;
mUserTracker = userTracker;
mWifiInteractor = wifiInteractor;
+ mCommunalSceneInteractor = communalSceneInteractor;
mLogger = new DreamLogger(logBuffer, TAG);
// Register to receive show/hide updates for the system status bar. Our custom status bar
@@ -172,6 +177,12 @@
network -> updateWifiUnavailableStatusIcon(
network instanceof WifiNetworkModel.Active));
+ collectFlow(
+ mView,
+ mCommunalSceneInteractor.isCommunalVisible(),
+ this::onCommunalVisibleChanged
+ );
+
mNextAlarmController.addCallback(mNextAlarmCallback);
updateAlarmStatusIcon();
@@ -230,9 +241,15 @@
mView.setTranslationY(translationY);
}
+ private void onCommunalVisibleChanged(boolean visible) {
+ mCommunalVisible = visible;
+ updateVisibility();
+ }
+
private boolean shouldShowStatusBar() {
- return !mDreamOverlayStateController.isLowLightActive()
- && !mStatusBarWindowStateController.windowIsShowing();
+ return (!mDreamOverlayStateController.isLowLightActive()
+ && !mStatusBarWindowStateController.windowIsShowing())
+ || mCommunalVisible;
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
index c30aea0..72312b8 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
@@ -16,6 +16,7 @@
package com.android.systemui.bluetooth.qsdialog
+import android.bluetooth.BluetoothDevice
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.BluetoothTileDialogLog
@@ -103,4 +104,29 @@
fun logDeviceUiUpdate(duration: Long) =
logBuffer.log(TAG, DEBUG, { long1 = duration }, { "DeviceUiUpdate. duration=$long1" })
+
+ fun logDeviceClickInAudioSharingWhenEnabled(inAudioSharing: Boolean) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ { str1 = inAudioSharing.toString() },
+ { "DeviceClick. in audio sharing=$str1" }
+ )
+ }
+
+ fun logConnectedLeByGroupId(map: Map<Int, List<BluetoothDevice>>) {
+ logBuffer.log(TAG, DEBUG, { str1 = map.toString() }, { "ConnectedLeByGroupId. map=$str1" })
+ }
+
+ fun logLaunchSettingsCriteriaMatched(criteria: String, deviceItem: DeviceItem) {
+ logBuffer.log(
+ TAG,
+ DEBUG,
+ {
+ str1 = criteria
+ str2 = deviceItem.toString()
+ },
+ { "$str1. deviceItem=$str2" }
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
deleted file mode 100644
index 2e9169e..0000000
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogModule.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.bluetooth.qsdialog
-
-import com.android.systemui.dagger.SysUISingleton
-import dagger.Binds
-import dagger.Module
-
-@Module
-interface BluetoothTileDialogModule {
- @Binds
- @SysUISingleton
- fun bindDeviceItemActionInteractor(
- impl: DeviceItemActionInteractorImpl
- ): DeviceItemActionInteractor
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
index b592b8e..4a358c0 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogUiEvent.kt
@@ -35,7 +35,17 @@
CONNECTED_OTHER_DEVICE_DISCONNECT(1508),
@UiEvent(doc = "The auto on toggle is clicked") BLUETOOTH_AUTO_ON_TOGGLE_CLICKED(1617),
@UiEvent(doc = "The audio sharing button is clicked")
- BLUETOOTH_AUDIO_SHARING_BUTTON_CLICKED(1700);
+ BLUETOOTH_AUDIO_SHARING_BUTTON_CLICKED(1700),
+ @UiEvent(doc = "Currently broadcasting and a LE audio supported device is clicked")
+ LAUNCH_SETTINGS_IN_SHARING_LE_DEVICE_CLICKED(1717),
+ @UiEvent(doc = "Currently broadcasting and a non-LE audio supported device is clicked")
+ LAUNCH_SETTINGS_IN_SHARING_NON_LE_DEVICE_CLICKED(1718),
+ @UiEvent(
+ doc = "Not broadcasting, having one connected, another saved LE audio device is clicked"
+ )
+ LAUNCH_SETTINGS_NOT_SHARING_SAVED_LE_DEVICE_CLICKED(1719),
+ @UiEvent(doc = "Not broadcasting, one of the two connected LE audio devices is clicked")
+ LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED(1720);
override fun getId() = metricId
}
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
index 9311760..4dafa93 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractor.kt
@@ -16,32 +16,87 @@
package com.android.systemui.bluetooth.qsdialog
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothProfile
+import android.content.Intent
+import android.os.Bundle
+import android.provider.Settings
import com.android.internal.logging.UiEventLogger
+import com.android.settingslib.bluetooth.A2dpProfile
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.HeadsetProfile
+import com.android.settingslib.bluetooth.HearingAidProfile
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.bluetooth.qsdialog.DeviceItemActionInteractor.LaunchSettingsCriteria.Companion.getCurrentConnectedLeByGroupId
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.phone.SystemUIDialog
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
-/** Defines interface for click handling of a DeviceItem. */
-interface DeviceItemActionInteractor {
- suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog)
-}
-
@SysUISingleton
-open class DeviceItemActionInteractorImpl
+class DeviceItemActionInteractor
@Inject
constructor(
+ private val activityStarter: ActivityStarter,
+ private val dialogTransitionAnimator: DialogTransitionAnimator,
+ private val localBluetoothManager: LocalBluetoothManager?,
@Background private val backgroundDispatcher: CoroutineDispatcher,
private val logger: BluetoothTileDialogLogger,
private val uiEventLogger: UiEventLogger,
-) : DeviceItemActionInteractor {
+) {
+ private val leAudioProfile: LeAudioProfile?
+ get() = localBluetoothManager?.profileManager?.leAudioProfile
- override suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
+ private val assistantProfile: LocalBluetoothLeBroadcastAssistant?
+ get() = localBluetoothManager?.profileManager?.leAudioBroadcastAssistantProfile
+
+ private val launchSettingsCriteriaList: List<LaunchSettingsCriteria>
+ get() =
+ listOf(
+ InSharingClickedNoSource(localBluetoothManager, backgroundDispatcher, logger),
+ NotSharingClickedNonConnect(
+ leAudioProfile,
+ assistantProfile,
+ backgroundDispatcher,
+ logger
+ ),
+ NotSharingClickedConnected(
+ leAudioProfile,
+ assistantProfile,
+ backgroundDispatcher,
+ logger
+ )
+ )
+
+ suspend fun onClick(deviceItem: DeviceItem, dialog: SystemUIDialog) {
withContext(backgroundDispatcher) {
logger.logDeviceClick(deviceItem.cachedBluetoothDevice.address, deviceItem.type)
+ if (
+ BluetoothUtils.isAudioSharingEnabled() &&
+ localBluetoothManager != null &&
+ leAudioProfile != null &&
+ assistantProfile != null
+ ) {
+ val inAudioSharing = BluetoothUtils.isBroadcasting(localBluetoothManager)
+ logger.logDeviceClickInAudioSharingWhenEnabled(inAudioSharing)
+ val criteriaMatched =
+ launchSettingsCriteriaList.firstOrNull {
+ it.matched(inAudioSharing, deviceItem)
+ }
+ if (criteriaMatched != null) {
+ uiEventLogger.log(criteriaMatched.getClickUiEvent(deviceItem))
+ launchSettings(deviceItem.cachedBluetoothDevice.device, dialog)
+ return@withContext
+ }
+ }
deviceItem.cachedBluetoothDevice.apply {
when (deviceItem.type) {
DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE -> {
@@ -69,4 +124,184 @@
}
}
}
+
+ private fun launchSettings(device: BluetoothDevice, dialog: SystemUIDialog) {
+ val intent =
+ Intent(Settings.ACTION_BLUETOOTH_SETTINGS).apply {
+ putExtra(
+ EXTRA_SHOW_FRAGMENT_ARGUMENTS,
+ Bundle().apply {
+ putParcelable(LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE, device)
+ }
+ )
+ }
+ intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
+ activityStarter.postStartActivityDismissingKeyguard(
+ intent,
+ 0,
+ dialogTransitionAnimator.createActivityTransitionController(dialog)
+ )
+ }
+
+ private interface LaunchSettingsCriteria {
+ suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean
+
+ suspend fun getClickUiEvent(deviceItem: DeviceItem): BluetoothTileDialogUiEvent
+
+ companion object {
+ suspend fun getCurrentConnectedLeByGroupId(
+ leAudioProfile: LeAudioProfile,
+ assistantProfile: LocalBluetoothLeBroadcastAssistant,
+ @Background backgroundDispatcher: CoroutineDispatcher,
+ logger: BluetoothTileDialogLogger,
+ ): Map<Int, List<BluetoothDevice>> {
+ return withContext(backgroundDispatcher) {
+ assistantProfile
+ .getDevicesMatchingConnectionStates(
+ intArrayOf(BluetoothProfile.STATE_CONNECTED)
+ )
+ ?.filterNotNull()
+ ?.groupBy { leAudioProfile.getGroupId(it) }
+ ?.also { logger.logConnectedLeByGroupId(it) } ?: emptyMap()
+ }
+ }
+ }
+ }
+
+ private class InSharingClickedNoSource(
+ private val localBluetoothManager: LocalBluetoothManager?,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val logger: BluetoothTileDialogLogger,
+ ) : LaunchSettingsCriteria {
+ // If currently broadcasting and the clicked device is not connected to the source
+ override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
+ return withContext(backgroundDispatcher) {
+ val matched =
+ inAudioSharing &&
+ deviceItem.isMediaDevice &&
+ !BluetoothUtils.hasConnectedBroadcastSource(
+ deviceItem.cachedBluetoothDevice,
+ localBluetoothManager
+ )
+
+ if (matched) {
+ logger.logLaunchSettingsCriteriaMatched("InSharingClickedNoSource", deviceItem)
+ }
+
+ matched
+ }
+ }
+
+ override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
+ if (deviceItem.isLeAudioSupported)
+ BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_IN_SHARING_LE_DEVICE_CLICKED
+ else BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_IN_SHARING_NON_LE_DEVICE_CLICKED
+ }
+
+ private class NotSharingClickedNonConnect(
+ private val leAudioProfile: LeAudioProfile?,
+ private val assistantProfile: LocalBluetoothLeBroadcastAssistant?,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val logger: BluetoothTileDialogLogger,
+ ) : LaunchSettingsCriteria {
+ // If not broadcasting, having one device connected, and clicked on a not yet connected LE
+ // audio device
+ override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
+ return withContext(backgroundDispatcher) {
+ val matched =
+ leAudioProfile?.let { leAudio ->
+ assistantProfile?.let { assistant ->
+ !inAudioSharing &&
+ getCurrentConnectedLeByGroupId(
+ leAudio,
+ assistant,
+ backgroundDispatcher,
+ logger
+ )
+ .size == 1 &&
+ deviceItem.isNotConnectedLeAudioSupported
+ }
+ } ?: false
+
+ if (matched) {
+ logger.logLaunchSettingsCriteriaMatched(
+ "NotSharingClickedNonConnect",
+ deviceItem
+ )
+ }
+
+ matched
+ }
+ }
+
+ override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
+ BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_SAVED_LE_DEVICE_CLICKED
+ }
+
+ private class NotSharingClickedConnected(
+ private val leAudioProfile: LeAudioProfile?,
+ private val assistantProfile: LocalBluetoothLeBroadcastAssistant?,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val logger: BluetoothTileDialogLogger,
+ ) : LaunchSettingsCriteria {
+ // If not broadcasting, having two device connected, clicked on any connected LE audio
+ // devices
+ override suspend fun matched(inAudioSharing: Boolean, deviceItem: DeviceItem): Boolean {
+ return withContext(backgroundDispatcher) {
+ val matched =
+ leAudioProfile?.let { leAudio ->
+ assistantProfile?.let { assistant ->
+ !inAudioSharing &&
+ getCurrentConnectedLeByGroupId(
+ leAudio,
+ assistant,
+ backgroundDispatcher,
+ logger
+ )
+ .size == 2 &&
+ deviceItem.isActiveOrConnectedLeAudioSupported
+ }
+ } ?: false
+
+ if (matched) {
+ logger.logLaunchSettingsCriteriaMatched(
+ "NotSharingClickedConnected",
+ deviceItem
+ )
+ }
+
+ matched
+ }
+ }
+
+ override suspend fun getClickUiEvent(deviceItem: DeviceItem) =
+ BluetoothTileDialogUiEvent.LAUNCH_SETTINGS_NOT_SHARING_CONNECTED_LE_DEVICE_CLICKED
+ }
+
+ private companion object {
+ const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
+
+ val DeviceItem.isLeAudioSupported: Boolean
+ get() =
+ cachedBluetoothDevice.profiles.any { profile ->
+ profile is LeAudioProfile && profile.isEnabled(cachedBluetoothDevice.device)
+ }
+
+ val DeviceItem.isNotConnectedLeAudioSupported: Boolean
+ get() = type == DeviceItemType.SAVED_BLUETOOTH_DEVICE && isLeAudioSupported
+
+ val DeviceItem.isActiveOrConnectedLeAudioSupported: Boolean
+ get() =
+ (type == DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE ||
+ type == DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE) && isLeAudioSupported
+
+ val DeviceItem.isMediaDevice: Boolean
+ get() =
+ cachedBluetoothDevice.connectableProfiles.any {
+ it is A2dpProfile ||
+ it is HearingAidProfile ||
+ it is LeAudioProfile ||
+ it is HeadsetProfile
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
index 9d110e6..10d6881 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt
@@ -29,6 +29,7 @@
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.util.kotlin.Quad
+import com.android.systemui.utils.coroutines.flow.mapLatestConflated
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -37,6 +38,7 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -96,7 +98,16 @@
.filter { currentScene ->
currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen
}
- .map { it == Scenes.Gone }
+ .mapLatestConflated { scene ->
+ if (scene == Scenes.Gone) {
+ // Make sure device unlock status is definitely unlocked before we consider the
+ // device "entered".
+ deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
+ true
+ } else {
+ false
+ }
+ }
.stateIn(
scope = applicationScope,
started = SharingStarted.Eagerly,
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index 4ac0c56..9d6c2bf 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.display.data.repository
+import android.annotation.SuppressLint
import android.hardware.display.DisplayManager
import android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED
import android.hardware.display.DisplayManager.DisplayListener
@@ -27,6 +28,7 @@
import android.view.Display
import com.android.app.tracing.FlowTracing.traceEach
import com.android.app.tracing.traceSection
+import com.android.systemui.Flags
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
@@ -42,11 +44,12 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
@@ -91,6 +94,7 @@
}
@SysUISingleton
+@SuppressLint("SharedFlowCreation")
class DisplayRepositoryImpl
@Inject
constructor(
@@ -132,8 +136,50 @@
allDisplayEvents.filterIsInstance<DisplayEvent.Changed>().map { event -> event.displayId }
override val displayAdditionEvent: Flow<Display?> =
- allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map {
- displayManager.getDisplay(it.displayId)
+ allDisplayEvents.filterIsInstance<DisplayEvent.Added>().map { getDisplay(it.displayId) }
+
+ private val oldEnabledDisplays: Flow<Set<Display>> =
+ allDisplayEvents
+ .map { getDisplays() }
+ .shareIn(bgApplicationScope, started = SharingStarted.WhileSubscribed(), replay = 1)
+
+ /** Propagate to the listeners only enabled displays */
+ private val enabledDisplayIds: Flow<Set<Int>> =
+ if (Flags.enableEfficientDisplayRepository()) {
+ allDisplayEvents
+ .scan(initial = emptySet()) { previousIds: Set<Int>, event: DisplayEvent ->
+ val id = event.displayId
+ when (event) {
+ is DisplayEvent.Removed -> previousIds - id
+ is DisplayEvent.Added,
+ is DisplayEvent.Changed -> previousIds + id
+ }
+ }
+ .shareIn(
+ bgApplicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ replay = 1
+ )
+ } else {
+ oldEnabledDisplays.map { enabledDisplaysSet ->
+ enabledDisplaysSet.map { it.displayId }.toSet()
+ }
+ }
+ .debugLog("enabledDisplayIds")
+
+ /**
+ * Represents displays that went though the [DisplayListener.onDisplayAdded] callback.
+ *
+ * Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
+ */
+ private val enabledDisplays: Flow<Set<Display>> =
+ if (Flags.enableEfficientDisplayRepository()) {
+ enabledDisplayIds
+ .mapElementsLazily { displayId -> getDisplay(displayId) }
+ .flowOn(backgroundCoroutineDispatcher)
+ .debugLog("enabledDisplayIds")
+ } else {
+ oldEnabledDisplays
}
/**
@@ -141,35 +187,26 @@
*
* Those are commonly the ones provided by [DisplayManager.getDisplays] by default.
*/
- private val enabledDisplays =
- allDisplayEvents
- .map { getDisplays() }
- .shareIn(bgApplicationScope, started = SharingStarted.WhileSubscribed(), replay = 1)
-
override val displays: Flow<Set<Display>> = enabledDisplays
private fun getDisplays(): Set<Display> =
traceSection("$TAG#getDisplays()") { displayManager.displays?.toSet() ?: emptySet() }
- /** Propagate to the listeners only enabled displays */
- private val enabledDisplayIds: Flow<Set<Int>> =
- enabledDisplays
- .map { enabledDisplaysSet -> enabledDisplaysSet.map { it.displayId }.toSet() }
- .debugLog("enabledDisplayIds")
-
private val _ignoredDisplayIds = MutableStateFlow<Set<Int>>(emptySet())
private val ignoredDisplayIds: Flow<Set<Int>> = _ignoredDisplayIds.debugLog("ignoredDisplayIds")
private fun getInitialConnectedDisplays(): Set<Int> =
- displayManager
- .getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)
- .map { it.displayId }
- .toSet()
- .also {
- if (DEBUG) {
- Log.d(TAG, "getInitialConnectedDisplays: $it")
+ traceSection("$TAG#getInitialConnectedDisplays") {
+ displayManager
+ .getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)
+ .map { it.displayId }
+ .toSet()
+ .also {
+ if (DEBUG) {
+ Log.d(TAG, "getInitialConnectedDisplays: $it")
+ }
}
- }
+ }
/* keeps connected displays until they are disconnected. */
private val connectedDisplayIds: StateFlow<Set<Int>> =
@@ -230,6 +267,9 @@
private fun getDisplayType(displayId: Int): Int? =
traceSection("$TAG#getDisplayType") { displayManager.getDisplay(displayId)?.type }
+ private fun getDisplay(displayId: Int): Display? =
+ traceSection("$TAG#getDisplay") { displayManager.getDisplay(displayId) }
+
/**
* Pending displays are the ones connected, but not enabled and not ignored.
*
@@ -307,6 +347,30 @@
}
}
+ /**
+ * Maps a set of T to a set of V, minimizing the number of `createValue` calls taking into
+ * account the diff between each root flow emission.
+ *
+ * This is needed to minimize the number of [getDisplay] in this class. Note that if the
+ * [createValue] returns a null element, it will not be added in the output set.
+ */
+ private fun <T, V> Flow<Set<T>>.mapElementsLazily(createValue: (T) -> V?): Flow<Set<V>> {
+ var initialSet = emptySet<T>()
+ val currentMap = mutableMapOf<T, V>()
+ var resultSet = emptySet<V>()
+ return onEach { currentSet ->
+ val removed = initialSet - currentSet
+ val added = currentSet - initialSet
+ if (added.isNotEmpty() || removed.isNotEmpty()) {
+ added.forEach { key: T -> createValue(key)?.let { currentMap[key] = it } }
+ removed.forEach { key: T -> currentMap.remove(key) }
+ resultSet = currentMap.values.toSet() // Creates a **copy** of values
+ }
+ initialSet = currentSet
+ }
+ .map { resultSet }
+ }
+
private companion object {
const val TAG = "DisplayRepository"
val DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Compile.IS_DEBUG
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 48660f2..a595eeb 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
@@ -50,6 +50,7 @@
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
@@ -77,7 +78,7 @@
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
+import kotlinx.coroutines.flow.transform
/**
* Encapsulates business-logic related to the keyguard but not to a more specific part within it.
@@ -111,7 +112,7 @@
keyguardTransitionInteractor.transitionState.map { step ->
val startingProgress = lastChangeStep.value
val progress = step.value
- if (step.to == AOD && progress >= startingProgress) {
+ if (step.to == AOD && progress >= startingProgress && startingProgress < 1f) {
val adjustedProgress =
((progress - startingProgress) / (1F - startingProgress)).coerceIn(
0F,
@@ -327,28 +328,35 @@
* This uses legacyShadeExpansion to process swipe up events. In the future, the touch input
* signal should be sent directly to transitions.
*/
- val dismissAlpha: Flow<Float?> =
+ val dismissAlpha: Flow<Float> =
shadeRepository.legacyShadeExpansion
- .filter { it < 1f }
.sampleCombine(
statusBarState,
keyguardTransitionInteractor.currentKeyguardState,
+ keyguardTransitionInteractor.transitionState,
isKeyguardDismissible,
)
- .map {
- (legacyShadeExpansion, statusBarState, currentKeyguardState, isKeyguardDismissible)
- ->
+ .filter { (_, _, _, step, _) -> !step.transitionState.isTransitioning() }
+ .transform {
+ (
+ legacyShadeExpansion,
+ statusBarState,
+ currentKeyguardState,
+ step,
+ isKeyguardDismissible) ->
if (
statusBarState == StatusBarState.KEYGUARD &&
isKeyguardDismissible &&
- currentKeyguardState == LOCKSCREEN
+ currentKeyguardState == LOCKSCREEN &&
+ legacyShadeExpansion != 1f
) {
- MathUtils.constrainedMap(0f, 1f, 0.95f, 1f, legacyShadeExpansion)
- } else {
- null
+ emit(MathUtils.constrainedMap(0f, 1f, 0.95f, 1f, legacyShadeExpansion))
+ } else if (legacyShadeExpansion == 0f || legacyShadeExpansion == 1f) {
+ // Resets alpha state
+ emit(1f)
}
}
- .onStart { emit(null) }
+ .onStart { emit(1f) }
.distinctUntilChanged()
val keyguardTranslationY: Flow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
index 3a43b1c..069f65b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt
@@ -105,7 +105,17 @@
is ObservableTransitionState.Transition ->
when {
transitionState.fromScene == Scenes.Lockscreen &&
- transitionState.toScene == Scenes.Gone -> flowOf(true)
+ transitionState.toScene == Scenes.Gone ->
+ sceneInteractor
+ .get()
+ .isTransitionUserInputOngoing
+ .flatMapLatestConflated { isUserInputOngoing ->
+ if (isUserInputOngoing) {
+ isDeviceEntered
+ } else {
+ flowOf(true)
+ }
+ }
transitionState.fromScene == Scenes.Bouncer &&
transitionState.toScene == Scenes.Gone ->
transitionState.progress.map { progress ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index 940f423..f5c521a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -32,6 +32,7 @@
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -48,6 +49,7 @@
constructor(
keyguardClockInteractor: KeyguardClockInteractor,
@Application private val applicationScope: CoroutineScope,
+ aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
notifsKeyguardInteractor: NotificationsKeyguardInteractor,
@get:VisibleForTesting val shadeInteractor: ShadeInteractor,
private val systemBarUtils: SystemBarUtilsProxy,
@@ -105,8 +107,13 @@
initialValue = false
)
- val isAodIconsVisible: StateFlow<Boolean> =
- notifsKeyguardInteractor.areNotificationsFullyHidden.stateIn(
+ // To translate elements below smartspace in weather clock to avoid overlapping between date
+ // element in weather clock and aod icons
+ val isAodIconsVisible: StateFlow<Boolean> = combine(aodNotificationIconViewModel.icons.map {
+ it.visibleIcons.isNotEmpty()
+ }, notifsKeyguardInteractor.areNotificationsFullyHidden) { hasIcons, visible ->
+ hasIcons && visible
+ }.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
initialValue = false
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 5027524..aefff7d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -66,7 +66,6 @@
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
@@ -236,7 +235,7 @@
// value emitted by any of them. Do not add flows that cannot make this guarantee.
merge(
alphaOnShadeExpansion,
- keyguardInteractor.dismissAlpha.filterNotNull(),
+ keyguardInteractor.dismissAlpha,
alternateBouncerToGoneTransitionViewModel.lockscreenAlpha(viewState),
aodToGoneTransitionViewModel.lockscreenAlpha(viewState),
aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
index 220d326..6a91d1b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
@@ -218,7 +218,7 @@
mediaFromRecPackageName = null
_currentMedia.value = sortedMap.values.toList()
}
- } else if (sortedMap.size > sortedMedia.size && it.active) {
+ } else if (sortedMap.size > _currentMedia.value.size && it.active) {
_currentMedia.value = sortedMap.values.toList()
} else {
// When loading an update for an existing media control.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
index fbb84de..4496b25 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaItem.java
@@ -16,7 +16,9 @@
package com.android.systemui.media.dialog;
-import androidx.annotation.IntDef;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.res.R;
@@ -46,40 +48,50 @@
int TYPE_PAIR_NEW_DEVICE = 2;
}
- public MediaItem() {
- this.mMediaDeviceOptional = Optional.empty();
- this.mTitle = null;
- this.mMediaItemType = MediaItemType.TYPE_PAIR_NEW_DEVICE;
+ /**
+ * Returns a new {@link MediaItemType#TYPE_DEVICE} {@link MediaItem} with its {@link
+ * #getMediaDevice() media device} set to {@code device} and its title set to {@code device}'s
+ * name.
+ */
+ public static MediaItem createDeviceMediaItem(@NonNull MediaDevice device) {
+ return new MediaItem(device, device.getName(), MediaItemType.TYPE_DEVICE);
}
- public MediaItem(String title, int mediaItemType) {
- this.mMediaDeviceOptional = Optional.empty();
+ /**
+ * Returns a new {@link MediaItemType#TYPE_PAIR_NEW_DEVICE} {@link MediaItem} with both {@link
+ * #getMediaDevice() media device} and title set to {@code null}.
+ */
+ public static MediaItem createPairNewDeviceMediaItem() {
+ return new MediaItem(
+ /* device */ null, /* title */ null, MediaItemType.TYPE_PAIR_NEW_DEVICE);
+ }
+
+ /**
+ * Returns a new {@link MediaItemType#TYPE_GROUP_DIVIDER} {@link MediaItem} with the specified
+ * title and a {@code null} {@link #getMediaDevice() media device}.
+ */
+ public static MediaItem createGroupDividerMediaItem(@Nullable String title) {
+ return new MediaItem(/* device */ null, title, MediaItemType.TYPE_GROUP_DIVIDER);
+ }
+
+ private MediaItem(
+ @Nullable MediaDevice device, @Nullable String title, @MediaItemType int type) {
+ this.mMediaDeviceOptional = Optional.ofNullable(device);
this.mTitle = title;
- this.mMediaItemType = mediaItemType;
- }
-
- public MediaItem(MediaDevice mediaDevice) {
- this.mMediaDeviceOptional = Optional.of(mediaDevice);
- this.mTitle = mediaDevice.getName();
- this.mMediaItemType = MediaItemType.TYPE_DEVICE;
+ this.mMediaItemType = type;
}
public Optional<MediaDevice> getMediaDevice() {
return mMediaDeviceOptional;
}
- /**
- * Get layout id based on media item Type.
- */
- public static int getMediaLayoutId(int mediaItemType) {
- switch (mediaItemType) {
- case MediaItemType.TYPE_DEVICE:
- case MediaItemType.TYPE_PAIR_NEW_DEVICE:
- return R.layout.media_output_list_item_advanced;
- case MediaItemType.TYPE_GROUP_DIVIDER:
- default:
- return R.layout.media_output_list_group_divider;
- }
+ /** Get layout id based on media item Type. */
+ public static int getMediaLayoutId(@MediaItemType int mediaItemType) {
+ return switch (mediaItemType) {
+ case MediaItemType.TYPE_DEVICE, MediaItemType.TYPE_PAIR_NEW_DEVICE ->
+ R.layout.media_output_list_item_advanced;
+ default -> R.layout.media_output_list_group_divider;
+ };
}
public String getTitle() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index c2cfdbe..1e86563 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -68,6 +68,7 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
+import com.android.internal.annotations.GuardedBy;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -656,10 +657,16 @@
if (DEBUG) {
Log.d(TAG, "No connected media device or muting expected device exist.");
}
- return categorizeMediaItems(null, devices, needToHandleMutingExpectedDevice);
+ return categorizeMediaItemsLocked(
+ /* connectedMediaDevice */ null,
+ devices,
+ needToHandleMutingExpectedDevice);
}
// selected device exist
- return categorizeMediaItems(connectedMediaDevice, devices, false);
+ return categorizeMediaItemsLocked(
+ connectedMediaDevice,
+ devices,
+ /* needToHandleMutingExpectedDevice */ false);
}
// To keep the same list order
final List<MediaDevice> targetMediaDevices = new ArrayList<>();
@@ -682,8 +689,9 @@
devices.removeAll(targetMediaDevices);
targetMediaDevices.addAll(devices);
}
- List<MediaItem> finalMediaItems = targetMediaDevices.stream().map(
- MediaItem::new).collect(Collectors.toList());
+ List<MediaItem> finalMediaItems = targetMediaDevices.stream()
+ .map(MediaItem::createDeviceMediaItem)
+ .collect(Collectors.toList());
dividerItems.forEach(finalMediaItems::add);
attachConnectNewDeviceItemIfNeeded(finalMediaItems);
return finalMediaItems;
@@ -694,51 +702,50 @@
* Initial categorization of current devices, will not be called for updates to the devices
* list.
*/
- private List<MediaItem> categorizeMediaItems(MediaDevice connectedMediaDevice,
+ @GuardedBy("mMediaDevicesLock")
+ private List<MediaItem> categorizeMediaItemsLocked(MediaDevice connectedMediaDevice,
List<MediaDevice> devices,
boolean needToHandleMutingExpectedDevice) {
- synchronized (mMediaDevicesLock) {
- List<MediaItem> finalMediaItems = new ArrayList<>();
- Set<String> selectedDevicesIds = getSelectedMediaDevice().stream().map(
- MediaDevice::getId).collect(Collectors.toSet());
- if (connectedMediaDevice != null) {
- selectedDevicesIds.add(connectedMediaDevice.getId());
- }
- boolean suggestedDeviceAdded = false;
- boolean displayGroupAdded = false;
- for (MediaDevice device : devices) {
- if (needToHandleMutingExpectedDevice && device.isMutingExpectedDevice()) {
- finalMediaItems.add(0, new MediaItem(device));
- } else if (!needToHandleMutingExpectedDevice && selectedDevicesIds.contains(
- device.getId())) {
- finalMediaItems.add(0, new MediaItem(device));
- } else {
- if (device.isSuggestedDevice() && !suggestedDeviceAdded) {
- attachGroupDivider(finalMediaItems, mContext.getString(
- R.string.media_output_group_title_suggested_device));
- suggestedDeviceAdded = true;
- } else if (!device.isSuggestedDevice() && !displayGroupAdded) {
- attachGroupDivider(finalMediaItems, mContext.getString(
- R.string.media_output_group_title_speakers_and_displays));
- displayGroupAdded = true;
- }
- finalMediaItems.add(new MediaItem(device));
- }
- }
- attachConnectNewDeviceItemIfNeeded(finalMediaItems);
- return finalMediaItems;
+ List<MediaItem> finalMediaItems = new ArrayList<>();
+ Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
+ .map(MediaDevice::getId)
+ .collect(Collectors.toSet());
+ if (connectedMediaDevice != null) {
+ selectedDevicesIds.add(connectedMediaDevice.getId());
}
+ boolean suggestedDeviceAdded = false;
+ boolean displayGroupAdded = false;
+ for (MediaDevice device : devices) {
+ if (needToHandleMutingExpectedDevice && device.isMutingExpectedDevice()) {
+ finalMediaItems.add(0, MediaItem.createDeviceMediaItem(device));
+ } else if (!needToHandleMutingExpectedDevice && selectedDevicesIds.contains(
+ device.getId())) {
+ finalMediaItems.add(0, MediaItem.createDeviceMediaItem(device));
+ } else {
+ if (device.isSuggestedDevice() && !suggestedDeviceAdded) {
+ attachGroupDivider(finalMediaItems, mContext.getString(
+ R.string.media_output_group_title_suggested_device));
+ suggestedDeviceAdded = true;
+ } else if (!device.isSuggestedDevice() && !displayGroupAdded) {
+ attachGroupDivider(finalMediaItems, mContext.getString(
+ R.string.media_output_group_title_speakers_and_displays));
+ displayGroupAdded = true;
+ }
+ finalMediaItems.add(MediaItem.createDeviceMediaItem(device));
+ }
+ }
+ attachConnectNewDeviceItemIfNeeded(finalMediaItems);
+ return finalMediaItems;
}
private void attachGroupDivider(List<MediaItem> mediaItems, String title) {
- mediaItems.add(
- new MediaItem(title, MediaItem.MediaItemType.TYPE_GROUP_DIVIDER));
+ mediaItems.add(MediaItem.createGroupDividerMediaItem(title));
}
private void attachConnectNewDeviceItemIfNeeded(List<MediaItem> mediaItems) {
// Attach "Connect a device" item only when current output is not remote and not a group
if (!isCurrentConnectedDeviceRemote() && getSelectedMediaDevice().size() == 1) {
- mediaItems.add(new MediaItem());
+ mediaItems.add(MediaItem.createPairNewDeviceMediaItem());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt
index 1d5f6f5..de300b2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/model/MediaProjectionState.kt
@@ -20,7 +20,21 @@
/** Represents the state of media projection. */
sealed interface MediaProjectionState {
- object NotProjecting : MediaProjectionState
- object EntireScreen : MediaProjectionState
- data class SingleTask(val task: RunningTaskInfo) : MediaProjectionState
+ /** There is no media being projected. */
+ data object NotProjecting : MediaProjectionState
+
+ /**
+ * Media is currently being projected.
+ *
+ * @property hostPackage the package name of the app that is receiving the content of the media
+ * projection (aka which app the phone screen contents are being sent to).
+ */
+ sealed class Projecting(open val hostPackage: String) : MediaProjectionState {
+ /** The entire screen is being projected. */
+ data class EntireScreen(override val hostPackage: String) : Projecting(hostPackage)
+
+ /** Only a single task is being projected. */
+ data class SingleTask(override val hostPackage: String, val task: RunningTaskInfo) :
+ Projecting(hostPackage)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
index 3ce0a1e0..8a9adc7 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepository.kt
@@ -64,6 +64,10 @@
}
}
+ override suspend fun stopProjecting() {
+ withContext(backgroundDispatcher) { mediaProjectionManager.stopActiveProjection() }
+ }
+
override val mediaProjectionState: Flow<MediaProjectionState> =
conflatedCallbackFlow {
val callback =
@@ -83,7 +87,9 @@
session: ContentRecordingSession?
) {
Log.d(TAG, "MediaProjectionManager.Callback#onSessionStarted: $session")
- launch { trySendWithFailureLogging(stateForSession(session), TAG) }
+ launch {
+ trySendWithFailureLogging(stateForSession(info, session), TAG)
+ }
}
}
mediaProjectionManager.addCallback(callback, handler)
@@ -95,19 +101,23 @@
initialValue = MediaProjectionState.NotProjecting,
)
- private suspend fun stateForSession(session: ContentRecordingSession?): MediaProjectionState {
+ private suspend fun stateForSession(
+ info: MediaProjectionInfo,
+ session: ContentRecordingSession?
+ ): MediaProjectionState {
if (session == null) {
return MediaProjectionState.NotProjecting
}
+
+ val hostPackage = info.packageName
if (session.contentToRecord == RECORD_CONTENT_DISPLAY || session.tokenToRecord == null) {
- return MediaProjectionState.EntireScreen
+ return MediaProjectionState.Projecting.EntireScreen(hostPackage)
}
val matchingTask =
tasksRepository.findRunningTaskFromWindowContainerToken(
checkNotNull(session.tokenToRecord)
- )
- ?: return MediaProjectionState.EntireScreen
- return MediaProjectionState.SingleTask(matchingTask)
+ ) ?: return MediaProjectionState.Projecting.EntireScreen(hostPackage)
+ return MediaProjectionState.Projecting.SingleTask(hostPackage, matchingTask)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
index 21300db..50182d7 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionRepository.kt
@@ -26,6 +26,9 @@
/** Switches the task that should be projected. */
suspend fun switchProjectedTask(task: RunningTaskInfo)
+ /** Stops the currently active projection. */
+ suspend fun stopProjecting()
+
/** Represents the current [MediaProjectionState]. */
val mediaProjectionState: Flow<MediaProjectionState>
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
index c232d4d..118639c 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
@@ -57,7 +57,7 @@
mediaProjectionRepository.mediaProjectionState.flatMapLatest { projectionState ->
Log.d(TAG, "MediaProjectionState -> $projectionState")
when (projectionState) {
- is MediaProjectionState.SingleTask -> {
+ is MediaProjectionState.Projecting.SingleTask -> {
val projectedTask = projectionState.task
tasksRepository.foregroundTask.map { foregroundTask ->
if (hasForegroundTaskSwitched(projectedTask, foregroundTask)) {
@@ -67,7 +67,7 @@
}
}
}
- is MediaProjectionState.EntireScreen,
+ is MediaProjectionState.Projecting.EntireScreen,
is MediaProjectionState.NotProjecting -> {
flowOf(TaskSwitchState.NotProjectingTask)
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 0e819c2..07289cb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -2028,12 +2028,15 @@
getBarTransitions().setBackgroundOverrideAlpha(1f);
}
}
- updateScreenPinningGestures();
+
+ // Update the window layout params when the nav mode changes as that will affect the
+ // system gesture insets
+ setNavBarMode(mode);
+ repositionNavigationBar(mCurrentRotation);
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
}
- setNavBarMode(mode);
mView.setShouldShowSwipeUpUi(mOverviewProxyService.shouldShowSwipeUpUI());
}
};
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 41cd2c4..99c95b5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -24,6 +24,7 @@
import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll;
import static com.android.systemui.navigationbar.gestural.Utilities.isTrackpadThreeFingerSwipe;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED;
import static java.util.stream.Collectors.joining;
@@ -1021,8 +1022,10 @@
if (mIsTrackpadThreeFingerSwipe) {
// Trackpad back gestures don't have zones, so we don't need to check if the down
// event is within insets.
- mAllowGesture = isBackAllowedCommon && isValidTrackpadBackGesture(
- true /* isTrackpadEvent */);
+ boolean trackpadGesturesEnabled =
+ (mSysUiFlags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0;
+ mAllowGesture = isBackAllowedCommon && trackpadGesturesEnabled
+ && isValidTrackpadBackGesture(true /* isTrackpadEvent */);
} else {
mAllowGesture = isBackAllowedCommon && !mUsingThreeButtonNav && isWithinInsets
&& isWithinTouchRegion((int) ev.getX(), (int) ev.getY())
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index ea89be6..b705a03 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.os.Handler;
-import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogModule;
import com.android.systemui.dagger.NightDisplayListenerModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
@@ -61,7 +60,6 @@
*/
@Module(subcomponents = {QSFragmentComponent.class, QSSceneComponent.class},
includes = {
- BluetoothTileDialogModule.class,
MediaModule.class,
PanelsModule.class,
QSExternalModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
index 79720c1..5637115 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
@@ -35,6 +35,7 @@
import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
import com.android.systemui.screenrecord.RecordingController
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
+import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
@@ -47,6 +48,7 @@
@Application private val context: Context,
@Main private val mainContext: CoroutineContext,
@Background private val backgroundContext: CoroutineContext,
+ private val screenRecordRepository: ScreenRecordRepository,
private val recordingController: RecordingController,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardDismissUtil: KeyguardDismissUtil,
@@ -65,8 +67,7 @@
Log.d(TAG, "Cancelling countdown")
withContext(backgroundContext) { recordingController.cancelCountdown() }
}
- is ScreenRecordModel.Recording ->
- withContext(backgroundContext) { recordingController.stopRecording() }
+ is ScreenRecordModel.Recording -> screenRecordRepository.stopRecording()
is ScreenRecordModel.DoingNothing ->
withContext(mainContext) {
showPrompt(action.expandable, user.identifier)
@@ -122,8 +123,7 @@
controller,
animateBackgroundBoundsChange = true,
)
- }
- ?: dialog.show()
+ } ?: dialog.show()
} else {
dialog.show()
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 0304e73..1e689bd 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -39,6 +39,7 @@
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.deviceentry.shared.model.DeviceUnlockSource
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor
import com.android.systemui.model.SceneContainerPlugin
import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
@@ -81,6 +82,7 @@
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.filterNot
+import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -120,6 +122,7 @@
private val uiEventLogger: UiEventLogger,
private val sceneBackInteractor: SceneBackInteractor,
private val shadeSessionStorage: SessionStorage,
+ private val windowMgrLockscreenVisInteractor: WindowManagerLockscreenVisibilityInteractor,
) : CoreStartable {
private val centralSurfaces: CentralSurfaces?
get() = centralSurfacesOptLazy.get().getOrNull()
@@ -227,6 +230,25 @@
handleDeviceUnlockStatus()
handlePowerState()
handleShadeTouchability()
+ handleSurfaceBehindKeyguardVisibility()
+ }
+
+ private fun handleSurfaceBehindKeyguardVisibility() {
+ applicationScope.launch {
+ sceneInteractor.currentScene.collectLatest { currentScene ->
+ if (currentScene == Scenes.Lockscreen) {
+ // Wait for surface to become visible
+ windowMgrLockscreenVisInteractor.surfaceBehindVisibility.first { it }
+ // Make sure the device is actually unlocked before force-changing the scene
+ deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked }
+ // Override the current transition, if any, by forcing the scene to Gone
+ sceneInteractor.changeScene(
+ toScene = Scenes.Gone,
+ loggingReason = "surface behind keyguard is visible",
+ )
+ }
+ }
+ }
}
private fun handleBouncerImeVisibility() {
@@ -329,8 +351,7 @@
Scenes.Gone to "device was unlocked in Bouncer scene"
} else {
val prevScene = previousScene.value
- (prevScene
- ?: Scenes.Gone) to
+ (prevScene ?: Scenes.Gone) to
"device was unlocked in Bouncer scene, from sceneKey=$prevScene"
}
isOnLockscreen ->
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
index d59d220..9eeb3b9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
@@ -28,6 +28,7 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
/**
* Repository storing information about the state of screen recording.
@@ -38,6 +39,9 @@
interface ScreenRecordRepository {
/** The current screen recording state. Note that this is a cold flow. */
val screenRecordState: Flow<ScreenRecordModel>
+
+ /** Stops the recording. */
+ suspend fun stopRecording()
}
@SysUISingleton
@@ -90,4 +94,8 @@
ScreenRecordModel.DoingNothing
}
}
+
+ override suspend fun stopRecording() {
+ withContext(bgCoroutineContext) { recordingController.stopRecording() }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
index 14659e7..f463cb5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
@@ -47,6 +47,7 @@
viewsIdToTranslate =
setOf(
ViewIdToTranslate(R.id.quick_settings_panel, START, filterShade),
+ ViewIdToTranslate(R.id.qs_footer_actions, START, filterShade),
ViewIdToTranslate(R.id.notification_stack_scroller, END, filterShade)),
progressProvider = progressProvider)
}
@@ -55,9 +56,8 @@
UnfoldConstantTranslateAnimator(
viewsIdToTranslate =
setOf(
- ViewIdToTranslate(R.id.statusIcons, END, filterShade),
+ ViewIdToTranslate(R.id.shade_header_system_icons, END, filterShade),
ViewIdToTranslate(R.id.privacy_container, END, filterShade),
- ViewIdToTranslate(R.id.batteryRemainingIcon, END, filterShade),
ViewIdToTranslate(R.id.carrier_group, END, filterShade),
ViewIdToTranslate(R.id.clock, START, filterShade),
ViewIdToTranslate(R.id.date, START, filterShade)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 3826b50..262befc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -537,8 +537,6 @@
private final KeyguardMediaController mKeyguardMediaController;
private final Optional<KeyguardUnfoldTransition> mKeyguardUnfoldTransition;
- private final Optional<NotificationPanelUnfoldAnimationController>
- mNotificationPanelUnfoldAnimationController;
/** The drag distance required to fully expand the split shade. */
private int mSplitShadeFullTransitionDistance;
@@ -964,8 +962,6 @@
mKeyguardUnfoldTransition = unfoldComponent.map(
SysUIUnfoldComponent::getKeyguardUnfoldTransition);
- mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
- SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
updateUserSwitcherFlags();
mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
@@ -1131,9 +1127,6 @@
mShadeHeaderController.init();
mShadeHeaderController.setShadeCollapseAction(
() -> collapse(/* delayed= */ false , /* speedUpFactor= */ 1.0f));
- mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
- mNotificationPanelUnfoldAnimationController.ifPresent(controller ->
- controller.setup(mNotificationContainerParent));
// Dreaming->Lockscreen
collectFlow(
@@ -1511,9 +1504,6 @@
if (!KeyguardBottomAreaRefactor.isEnabled()) {
setKeyguardBottomAreaVisibility(mBarState, false);
}
-
- mKeyguardUnfoldTransition.ifPresent(u -> u.setup(mView));
- mNotificationPanelUnfoldAnimationController.ifPresent(u -> u.setup(mView));
}
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
@@ -1797,6 +1787,7 @@
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean shouldBeCentered = shouldKeyguardStatusViewBeCentered();
+ mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered));
if (MigrateClocksToBlueprint.isEnabled()) {
mKeyguardInteractor.setClockShouldBeCentered(shouldBeCentered);
return;
@@ -1804,7 +1795,6 @@
ConstraintLayout layout = mNotificationContainerParent;
mKeyguardStatusViewController.updateAlignment(
layout, mSplitShadeEnabled, shouldBeCentered, animate);
- mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered));
}
private boolean shouldKeyguardStatusViewBeCentered() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 1df085b..e41f99b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -32,6 +32,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AuthKeyguardMessageArea;
+import com.android.keyguard.KeyguardUnfoldTransition;
import com.android.keyguard.LockIconViewController;
import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityTransitionAnimator;
@@ -72,6 +73,7 @@
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
+import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.util.time.SystemClock;
@@ -174,6 +176,7 @@
DozeScrimController dozeScrimController,
NotificationShadeWindowController controller,
Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider,
+ Optional<SysUIUnfoldComponent> unfoldComponent,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
NotificationInsetsController notificationInsetsController,
AmbientState ambientState,
@@ -234,6 +237,14 @@
notificationLaunchAnimationInteractor.isLaunchAnimationRunning(),
this::setExpandAnimationRunning);
+ var keyguardUnfoldTransition = unfoldComponent.map(
+ SysUIUnfoldComponent::getKeyguardUnfoldTransition);
+ var notificationPanelUnfoldAnimationController = unfoldComponent.map(
+ SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
+
+ keyguardUnfoldTransition.ifPresent(KeyguardUnfoldTransition::setup);
+ notificationPanelUnfoldAnimationController.ifPresent(u -> u.setup(mView));
+
mClock = clock;
if (featureFlagsClassic.isEnabled(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION)) {
unfoldTransitionProgressProvider.ifPresent(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index 6c76061..b2e0cd0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -30,6 +30,9 @@
import com.android.systemui.privacy.OngoingPrivacyChip
import com.android.systemui.privacy.PrivacyItem
import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.TransitionKeys
import com.android.systemui.shade.domain.interactor.PrivacyChipInteractor
import com.android.systemui.shade.domain.interactor.ShadeHeaderClockInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -57,6 +60,7 @@
@Application private val applicationScope: CoroutineScope,
context: Context,
private val activityStarter: ActivityStarter,
+ private val sceneInteractor: SceneInteractor,
shadeInteractor: ShadeInteractor,
mobileIconsInteractor: MobileIconsInteractor,
val mobileIconsViewModel: MobileIconsViewModel,
@@ -139,6 +143,15 @@
clockInteractor.launchClockActivity()
}
+ /** Notifies that the system icons container was clicked. */
+ fun onSystemIconContainerClicked() {
+ sceneInteractor.changeScene(
+ SceneFamilies.Home,
+ "ShadeHeaderViewModel.onSystemIconContainerClicked",
+ TransitionKeys.SlightlyFasterShadeCollapse,
+ )
+ }
+
/** Notifies that the shadeCarrierGroup was clicked. */
fun onShadeCarrierGroupClicked() {
activityStarter.postStartActivityDismissingKeyguard(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
index c3d37fb..086a32d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
@@ -16,11 +16,37 @@
package com.android.systemui.statusbar.chips.domain.interactor
+import android.view.View
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.phone.SystemUIDialog
import kotlinx.coroutines.flow.StateFlow
/** Interface for an interactor that knows the state of a single type of ongoing activity chip. */
interface OngoingActivityChipInteractor {
/** A flow modeling the chip that should be shown. */
val chip: StateFlow<OngoingActivityChipModel>
+
+ companion object {
+ /** Creates a chip click listener that launches a dialog created by [dialogDelegate]. */
+ fun createDialogLaunchOnClickListener(
+ dialogDelegate: SystemUIDialog.Delegate,
+ dialogTransitionAnimator: DialogTransitionAnimator,
+ ): View.OnClickListener {
+ return View.OnClickListener { view ->
+ val dialog = dialogDelegate.createDialog()
+ val launchableView =
+ view.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ // TODO(b/343699052): This makes a beautiful animate-in, but the
+ // animate-out looks odd because the dialog animates back into the chip
+ // but then the chip disappears. If we aren't able to address
+ // b/343699052 in time for launch, we should just use `dialog.show`.
+ dialogTransitionAnimator.showFromView(dialog, launchableView)
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
index ac16d26..6611434 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractor.kt
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
+import android.content.pm.PackageManager
+import androidx.annotation.DrawableRes
+import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
@@ -24,7 +27,12 @@
import com.android.systemui.mediaprojection.data.repository.MediaProjectionRepository
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndCastToOtherDeviceDialogDelegate
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndShareToAppDialogDelegate
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.Utils
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -32,6 +40,7 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/**
* Interactor for media-projection-related chips in the status bar.
@@ -47,33 +56,88 @@
class MediaProjectionChipInteractor
@Inject
constructor(
- @Application scope: CoroutineScope,
- mediaProjectionRepository: MediaProjectionRepository,
- val systemClock: SystemClock,
+ @Application private val scope: CoroutineScope,
+ private val mediaProjectionRepository: MediaProjectionRepository,
+ private val packageManager: PackageManager,
+ private val systemClock: SystemClock,
+ private val dialogFactory: SystemUIDialog.Factory,
+ private val dialogTransitionAnimator: DialogTransitionAnimator,
) : OngoingActivityChipInteractor {
override val chip: StateFlow<OngoingActivityChipModel> =
mediaProjectionRepository.mediaProjectionState
.map { state ->
when (state) {
is MediaProjectionState.NotProjecting -> OngoingActivityChipModel.Hidden
- is MediaProjectionState.EntireScreen,
- is MediaProjectionState.SingleTask -> {
- // TODO(b/332662551): Distinguish between cast-to-other-device and
- // share-to-app.
- OngoingActivityChipModel.Shown(
- icon =
- Icon.Resource(
- R.drawable.ic_cast_connected,
- ContentDescription.Resource(R.string.accessibility_casting)
- ),
- // TODO(b/332662551): See if we can use a MediaProjection API to fetch
- // this time.
- startTimeMs = systemClock.elapsedRealtime()
- ) {
- // TODO(b/332662551): Implement the pause dialog.
+ is MediaProjectionState.Projecting -> {
+ if (isProjectionToOtherDevice(state.hostPackage)) {
+ createCastToOtherDeviceChip()
+ } else {
+ createShareToAppChip()
}
}
}
}
.stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+
+ /** Stops the currently active projection. */
+ fun stopProjecting() {
+ scope.launch { mediaProjectionRepository.stopProjecting() }
+ }
+
+ /**
+ * Returns true iff projecting to the given [packageName] means that we're projecting to a
+ * *different* device (as opposed to projecting to some application on *this* device).
+ */
+ private fun isProjectionToOtherDevice(packageName: String?): Boolean {
+ // The [isHeadlessRemoteDisplayProvider] check approximates whether a projection is to a
+ // different device or the same device, because headless remote display packages are the
+ // only kinds of packages that do cast-to-other-device. This isn't exactly perfect,
+ // because it means that any projection by those headless remote display packages will be
+ // marked as going to a different device, even if that isn't always true. See b/321078669.
+ return Utils.isHeadlessRemoteDisplayProvider(packageManager, packageName)
+ }
+
+ private fun createCastToOtherDeviceChip(): OngoingActivityChipModel.Shown {
+ return OngoingActivityChipModel.Shown(
+ icon =
+ Icon.Resource(
+ CAST_TO_OTHER_DEVICE_ICON,
+ ContentDescription.Resource(R.string.accessibility_casting)
+ ),
+ // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
+ startTimeMs = systemClock.elapsedRealtime(),
+ createDialogLaunchOnClickListener(
+ castToOtherDeviceDialogDelegate,
+ dialogTransitionAnimator,
+ ),
+ )
+ }
+
+ private val castToOtherDeviceDialogDelegate =
+ EndCastToOtherDeviceDialogDelegate(
+ dialogFactory,
+ this@MediaProjectionChipInteractor,
+ )
+
+ private fun createShareToAppChip(): OngoingActivityChipModel.Shown {
+ return OngoingActivityChipModel.Shown(
+ // TODO(b/332662551): Use the right content description.
+ icon = Icon.Resource(SHARE_TO_APP_ICON, contentDescription = null),
+ // TODO(b/332662551): Maybe use a MediaProjection API to fetch this time.
+ startTimeMs = systemClock.elapsedRealtime(),
+ createDialogLaunchOnClickListener(shareToAppDialogDelegate, dialogTransitionAnimator),
+ )
+ }
+
+ private val shareToAppDialogDelegate =
+ EndShareToAppDialogDelegate(
+ dialogFactory,
+ this@MediaProjectionChipInteractor,
+ )
+
+ companion object {
+ // TODO(b/332662551): Use the right icon.
+ @DrawableRes val SHARE_TO_APP_ICON = R.drawable.ic_screenshot_share
+ @DrawableRes val CAST_TO_OTHER_DEVICE_ICON = R.drawable.ic_cast_connected
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegate.kt
new file mode 100644
index 0000000..33cec97
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegate.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.mediaprojection.ui.view
+
+import android.os.Bundle
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** A dialog that lets the user stop an ongoing cast-screen-to-other-device event. */
+class EndCastToOtherDeviceDialogDelegate(
+ private val systemUIDialogFactory: SystemUIDialog.Factory,
+ private val interactor: MediaProjectionChipInteractor,
+) : SystemUIDialog.Delegate {
+ override fun createDialog(): SystemUIDialog {
+ return systemUIDialogFactory.create(this)
+ }
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ with(dialog) {
+ setIcon(MediaProjectionChipInteractor.CAST_TO_OTHER_DEVICE_ICON)
+ setTitle(R.string.cast_to_other_device_stop_dialog_title)
+ // TODO(b/332662551): Use a different message if they're sharing just a single app.
+ setMessage(R.string.cast_to_other_device_stop_dialog_message)
+ // No custom on-click, because the dialog will automatically be dismissed when the
+ // button is clicked anyway.
+ setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
+ setPositiveButton(R.string.cast_to_other_device_stop_dialog_button) { _, _ ->
+ interactor.stopProjecting()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegate.kt
new file mode 100644
index 0000000..3a863b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegate.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.mediaprojection.ui.view
+
+import android.os.Bundle
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** A dialog that lets the user stop an ongoing share-screen-to-app event. */
+class EndShareToAppDialogDelegate(
+ private val systemUIDialogFactory: SystemUIDialog.Factory,
+ private val interactor: MediaProjectionChipInteractor,
+) : SystemUIDialog.Delegate {
+ override fun createDialog(): SystemUIDialog {
+ return systemUIDialogFactory.create(this)
+ }
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ with(dialog) {
+ setIcon(MediaProjectionChipInteractor.SHARE_TO_APP_ICON)
+ setTitle(R.string.share_to_app_stop_dialog_title)
+ // TODO(b/332662551): Use a different message if they're sharing just a single app.
+ setMessage(R.string.share_to_app_stop_dialog_message)
+ // No custom on-click, because the dialog will automatically be dismissed when the
+ // button is clicked anyway.
+ setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
+ setPositiveButton(R.string.share_to_app_stop_dialog_button) { _, _ ->
+ interactor.stopProjecting()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
index 585ff5f..4959b09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.chips.screenrecord.domain.interactor
+import androidx.annotation.DrawableRes
+import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -23,7 +25,10 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.ScreenRecordRepository
import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.screenrecord.ui.view.EndScreenRecordingDialogDelegate
+import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -31,15 +36,18 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Interactor for the screen recording chip shown in the status bar. */
@SysUISingleton
class ScreenRecordChipInteractor
@Inject
constructor(
- @Application scope: CoroutineScope,
- screenRecordRepository: ScreenRecordRepository,
- val systemClock: SystemClock,
+ @Application private val scope: CoroutineScope,
+ private val screenRecordRepository: ScreenRecordRepository,
+ private val systemClock: SystemClock,
+ private val dialogFactory: SystemUIDialog.Factory,
+ private val dialogTransitionAnimator: DialogTransitionAnimator,
) : OngoingActivityChipInteractor {
override val chip: StateFlow<OngoingActivityChipModel> =
screenRecordRepository.screenRecordState
@@ -51,16 +59,29 @@
is ScreenRecordModel.Recording ->
OngoingActivityChipModel.Shown(
// TODO(b/332662551): Also provide a content description.
- icon =
- Icon.Resource(
- R.drawable.stat_sys_screen_record,
- contentDescription = null
- ),
- startTimeMs = systemClock.elapsedRealtime()
- ) {
- // TODO(b/332662551): Implement the pause dialog.
- }
+ icon = Icon.Resource(ICON, contentDescription = null),
+ startTimeMs = systemClock.elapsedRealtime(),
+ createDialogLaunchOnClickListener(
+ dialogDelegate,
+ dialogTransitionAnimator
+ ),
+ )
}
}
.stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+
+ /** Stops the recording. */
+ fun stopRecording() {
+ scope.launch { screenRecordRepository.stopRecording() }
+ }
+
+ private val dialogDelegate =
+ EndScreenRecordingDialogDelegate(
+ dialogFactory,
+ this@ScreenRecordChipInteractor,
+ )
+
+ companion object {
+ @DrawableRes val ICON = R.drawable.ic_screenrecord
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegate.kt
new file mode 100644
index 0000000..b8e8cfa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegate.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.screenrecord.ui.view
+
+import android.os.Bundle
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** A dialog that lets the user stop an ongoing screen recording. */
+class EndScreenRecordingDialogDelegate(
+ private val systemUIDialogFactory: SystemUIDialog.Factory,
+ private val interactor: ScreenRecordChipInteractor,
+) : SystemUIDialog.Delegate {
+
+ override fun createDialog(): SystemUIDialog {
+ return systemUIDialogFactory.create(this)
+ }
+
+ override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) {
+ with(dialog) {
+ setIcon(ScreenRecordChipInteractor.ICON)
+ setTitle(R.string.screenrecord_stop_dialog_title)
+ // TODO(b/332662551): Use a different message if they're sharing just a single app.
+ setMessage(R.string.screenrecord_stop_dialog_message)
+ // No custom on-click, because the dialog will automatically be dismissed when the
+ // button is clicked anyway.
+ setNegativeButton(R.string.close_dialog_button, /* onClick= */ null)
+ setPositiveButton(R.string.screenrecord_stop_dialog_button) { _, _ ->
+ interactor.stopRecording()
+ }
+ }
+ }
+}
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 d1fabb1..9394249 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
@@ -358,11 +358,7 @@
* @param whenMillis
*/
public void setNotificationWhen(long whenMillis) {
- if (mNotificationHeader == null) {
- return;
- }
-
- final View timeView = mNotificationHeader.findViewById(com.android.internal.R.id.time);
+ final View timeView = mView.findViewById(com.android.internal.R.id.time);
if (timeView instanceof DateTimeView) {
((DateTimeView) timeView).setTime(whenMillis);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index 6a8c43a..b13630f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -53,6 +53,7 @@
import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.GoneToDreamingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionViewModel
@@ -120,6 +121,7 @@
private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel,
private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel,
+ private val goneToLockscreenTransitionViewModel: GoneToLockscreenTransitionViewModel,
private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel,
private val lockscreenToGlanceableHubTransitionViewModel:
LockscreenToGlanceableHubTransitionViewModel,
@@ -472,6 +474,9 @@
// All transition view models are mututally exclusive, and safe to merge
val alphaTransitions =
merge(
+ keyguardInteractor.dismissAlpha.dumpWhileCollecting(
+ "keyguardInteractor.dismissAlpha"
+ ),
alternateBouncerToGoneTransitionViewModel.notificationAlpha(viewState),
aodToGoneTransitionViewModel.notificationAlpha(viewState),
aodToLockscreenTransitionViewModel.notificationAlpha,
@@ -482,6 +487,7 @@
goneToAodTransitionViewModel.notificationAlpha,
goneToDreamingTransitionViewModel.lockscreenAlpha,
goneToDozingTransitionViewModel.lockscreenAlpha,
+ goneToLockscreenTransitionViewModel.lockscreenAlpha,
lockscreenToDreamingTransitionViewModel.lockscreenAlpha,
lockscreenToGoneTransitionViewModel.notificationAlpha(viewState),
lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
@@ -498,24 +504,12 @@
// These remaining cases handle alpha changes within an existing state, such as
// shade expansion or swipe to dismiss
combineTransform(
- isOnLockscreenWithoutShade,
isTransitioningToHiddenKeyguard,
- shadeCollapseFadeIn,
alphaForShadeAndQsExpansion,
- keyguardInteractor.dismissAlpha.dumpWhileCollecting(
- "keyguardInteractor.keyguardAlpha"
- ),
) {
- isOnLockscreenWithoutShade,
isTransitioningToHiddenKeyguard,
- shadeCollapseFadeIn,
- alphaForShadeAndQsExpansion,
- dismissAlpha ->
- if (isOnLockscreenWithoutShade) {
- if (!shadeCollapseFadeIn && dismissAlpha != null) {
- emit(dismissAlpha)
- }
- } else if (!isTransitioningToHiddenKeyguard) {
+ alphaForShadeAndQsExpansion ->
+ if (!isTransitioningToHiddenKeyguard) {
emit(alphaForShadeAndQsExpansion)
}
},
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index e44edcb..cd59d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -21,6 +21,7 @@
import static com.android.systemui.Flags.updateUserSwitcherBackground;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -46,6 +47,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.log.core.LogLevel;
@@ -83,6 +85,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -128,6 +131,7 @@
private final Executor mBackgroundExecutor;
private final Object mLock = new Object();
private final KeyguardLogger mLogger;
+ private final CommunalSceneInteractor mCommunalSceneInteractor;
private View mSystemIconsContainer;
private final StatusOverlayHoverListenerFactory mStatusOverlayHoverListenerFactory;
@@ -241,6 +245,12 @@
}
};
+ private boolean mCommunalShowing;
+
+ private final Consumer<Boolean> mCommunalConsumer = (communalShowing) -> {
+ mCommunalShowing = communalShowing;
+ updateViewState();
+ };
private final DisableStateTracker mDisableStateTracker;
@@ -298,7 +308,8 @@
@Main Executor mainExecutor,
@Background Executor backgroundExecutor,
KeyguardLogger logger,
- StatusOverlayHoverListenerFactory statusOverlayHoverListenerFactory
+ StatusOverlayHoverListenerFactory statusOverlayHoverListenerFactory,
+ CommunalSceneInteractor communalSceneInteractor
) {
super(view);
mCarrierTextController = carrierTextController;
@@ -324,6 +335,7 @@
mMainExecutor = mainExecutor;
mBackgroundExecutor = backgroundExecutor;
mLogger = logger;
+ mCommunalSceneInteractor = communalSceneInteractor;
mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
mKeyguardStateController.addCallback(
@@ -405,6 +417,7 @@
UserHandle.USER_ALL);
updateUserSwitcher();
onThemeChanged();
+ collectFlow(mView, mCommunalSceneInteractor.isCommunalVisible(), mCommunalConsumer);
}
@Override
@@ -559,6 +572,7 @@
&& !mDozing
&& !hideForBypass
&& !mDisableStateTracker.isDisabled()
+ && !mCommunalShowing
? View.VISIBLE : View.INVISIBLE;
updateViewState(newAlpha, newVisibility);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index a2ec1f2..44b5baf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -94,7 +94,7 @@
is OngoingActivityChipModel.Shown -> {
IconViewBinder.bind(chipModel.icon, chipIconView)
ChipChronometerBinder.bind(chipModel.startTimeMs, chipTimeView)
- // TODO(b/332662551): Attach click listener to chip
+ chipView.setOnClickListener(chipModel.onClickListener)
listener.onOngoingActivityStatusChanged(
hasOngoingActivity = true
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
index 7669524..11740a8 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TouchpadTutorialViewModel.kt
@@ -27,6 +27,10 @@
private val _screen = MutableStateFlow(Screen.TUTORIAL_SELECTION)
val screen: StateFlow<Screen> = _screen
+ fun goTo(screen: Screen) {
+ _screen.value = screen
+ }
+
class Factory @Inject constructor() : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt
deleted file mode 100644
index 1a8272d8..0000000
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/TutorialSelectionViewModel.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.touchpad.tutorial.ui
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-
-class TutorialSelectionViewModel : ViewModel()
-
-class TutorialSelectionViewModelFactory : ViewModelProvider.Factory {
-
- @Suppress("UNCHECKED_CAST")
- override fun <T : ViewModel> create(modelClass: Class<T>): T {
- return TutorialSelectionViewModel() as T
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index 09dd909..b7629c7 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -19,6 +19,7 @@
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.Lifecycle.State.STARTED
@@ -33,8 +34,6 @@
import com.android.systemui.touchpad.tutorial.ui.Screen.HOME_GESTURE
import com.android.systemui.touchpad.tutorial.ui.Screen.TUTORIAL_SELECTION
import com.android.systemui.touchpad.tutorial.ui.TouchpadTutorialViewModel
-import com.android.systemui.touchpad.tutorial.ui.TutorialSelectionViewModel
-import com.android.systemui.touchpad.tutorial.ui.TutorialSelectionViewModelFactory
import javax.inject.Inject
class TouchpadTutorialActivity
@@ -45,27 +44,31 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContent { PlatformTheme { TouchpadTutorialScreen(viewModelFactory) } }
+ enableEdgeToEdge()
+ setContent {
+ PlatformTheme { TouchpadTutorialScreen(viewModelFactory, closeTutorial = { finish() }) }
+ }
}
}
@Composable
-fun TouchpadTutorialScreen(viewModelFactory: ViewModelProvider.Factory) {
+fun TouchpadTutorialScreen(viewModelFactory: ViewModelProvider.Factory, closeTutorial: () -> Unit) {
val vm = viewModel<TouchpadTutorialViewModel>(factory = viewModelFactory)
val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED)
when (activeScreen) {
- TUTORIAL_SELECTION -> TutorialSelectionScreen()
+ TUTORIAL_SELECTION ->
+ TutorialSelectionScreen(
+ onBackTutorialClicked = { vm.goTo(BACK_GESTURE) },
+ onHomeTutorialClicked = { vm.goTo(HOME_GESTURE) },
+ onActionKeyTutorialClicked = {},
+ onDoneButtonClicked = closeTutorial
+ )
BACK_GESTURE -> BackGestureTutorialScreen()
HOME_GESTURE -> HomeGestureTutorialScreen()
}
}
@Composable
-fun TutorialSelectionScreen() {
- val vm = viewModel<TutorialSelectionViewModel>(factory = TutorialSelectionViewModelFactory())
-}
-
-@Composable
fun BackGestureTutorialScreen() {
val vm = viewModel<BackGestureTutorialViewModel>(factory = GestureViewModelFactory())
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt
new file mode 100644
index 0000000..532eb1b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TutorialSelectionScreen.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.touchpad.tutorial.ui.view
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import com.android.systemui.res.R
+
+@Composable
+fun TutorialSelectionScreen(
+ onBackTutorialClicked: () -> Unit,
+ onHomeTutorialClicked: () -> Unit,
+ onActionKeyTutorialClicked: () -> Unit,
+ onDoneButtonClicked: () -> Unit,
+) {
+ Column(
+ verticalArrangement = Arrangement.Center,
+ modifier =
+ Modifier.background(
+ color = MaterialTheme.colorScheme.surfaceContainer,
+ )
+ .fillMaxSize()
+ ) {
+ TutorialSelectionButtons(
+ onBackTutorialClicked = onBackTutorialClicked,
+ onHomeTutorialClicked = onHomeTutorialClicked,
+ onActionKeyTutorialClicked = onActionKeyTutorialClicked,
+ modifier = Modifier.padding(60.dp)
+ )
+ DoneButton(
+ onDoneButtonClicked = onDoneButtonClicked,
+ modifier = Modifier.padding(horizontal = 60.dp)
+ )
+ }
+}
+
+@Composable
+private fun TutorialSelectionButtons(
+ onBackTutorialClicked: () -> Unit,
+ onHomeTutorialClicked: () -> Unit,
+ onActionKeyTutorialClicked: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(20.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = modifier
+ ) {
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_back_gesture_button),
+ onClick = onBackTutorialClicked,
+ color = MaterialTheme.colorScheme.primary,
+ modifier = Modifier.weight(1f)
+ )
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_home_gesture_button),
+ onClick = onHomeTutorialClicked,
+ color = MaterialTheme.colorScheme.secondary,
+ modifier = Modifier.weight(1f)
+ )
+ TutorialButton(
+ text = stringResource(R.string.touchpad_tutorial_action_key_button),
+ onClick = onActionKeyTutorialClicked,
+ color = MaterialTheme.colorScheme.tertiary,
+ modifier = Modifier.weight(1f)
+ )
+ }
+}
+
+@Composable
+private fun TutorialButton(
+ text: String,
+ onClick: () -> Unit,
+ color: Color,
+ modifier: Modifier = Modifier
+) {
+ Button(
+ onClick = onClick,
+ shape = RoundedCornerShape(16.dp),
+ colors = ButtonDefaults.buttonColors(containerColor = color),
+ modifier = modifier.aspectRatio(0.66f)
+ ) {
+ Text(text = text, style = MaterialTheme.typography.headlineLarge)
+ }
+}
+
+@Composable
+private fun DoneButton(onDoneButtonClicked: () -> Unit, modifier: Modifier = Modifier) {
+ Row(
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = modifier.fillMaxWidth()
+ ) {
+ Button(onClick = onDoneButtonClicked) {
+ Text(stringResource(R.string.touchpad_tutorial_done_button))
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index a27989d..291903d 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -21,6 +21,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.NotificationPanelUnfoldAnimationController
import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController
+import com.android.systemui.unfold.dagger.NaturalRotation
import com.android.systemui.unfold.dagger.UnfoldBg
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider
@@ -108,6 +109,13 @@
abstract fun bindsFoldLightRevealOverlayAnimation(
anim: FoldLightRevealOverlayAnimation
): FullscreenLightRevealAnimation
+
+ @Binds
+ @NaturalRotation
+ @SysUIUnfoldScope
+ abstract fun bindNaturalRotationUnfoldProgressProvider(
+ provider: NaturalRotationUnfoldProgressProvider
+ ): UnfoldTransitionProgressProvider
}
@SysUIUnfoldScope
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
index 3afca59..336183d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUnfoldTransitionTest.kt
@@ -18,26 +18,25 @@
import android.testing.AndroidTestingRunner
import android.view.View
-import android.view.ViewGroup
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationShadeWindowView
import com.android.systemui.statusbar.StatusBarState.KEYGUARD
import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.unfold.FakeUnfoldTransitionProvider
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
-import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
-import com.android.systemui.util.mockito.capture
-import com.android.systemui.util.mockito.whenever
+import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
/**
* Translates items away/towards the hinge when the device is opened/closed. This is controlled by
@@ -47,11 +46,16 @@
@RunWith(AndroidTestingRunner::class)
class KeyguardUnfoldTransitionTest : SysuiTestCase() {
- @Mock private lateinit var progressProvider: NaturalRotationUnfoldProgressProvider
+ private val kosmos = Kosmos()
- @Captor private lateinit var progressListenerCaptor: ArgumentCaptor<TransitionProgressListener>
+ private val progressProvider: FakeUnfoldTransitionProvider =
+ kosmos.fakeUnfoldTransitionProgressProvider
- @Mock private lateinit var parent: ViewGroup
+ @Mock
+ private lateinit var keyguardRootView: KeyguardRootView
+
+ @Mock
+ private lateinit var notificationShadeWindowView: NotificationShadeWindowView
@Mock private lateinit var statusBarStateController: StatusBarStateController
@@ -66,13 +70,15 @@
xTranslationMax =
context.resources.getDimensionPixelSize(R.dimen.keyguard_unfold_translation_x).toFloat()
- underTest = KeyguardUnfoldTransition(context, statusBarStateController, progressProvider)
+ underTest = KeyguardUnfoldTransition(
+ context, keyguardRootView, notificationShadeWindowView,
+ statusBarStateController, progressProvider
+ )
- underTest.setup(parent)
+ underTest.setup()
underTest.statusViewCentered = false
- verify(progressProvider).addCallback(capture(progressListenerCaptor))
- progressListener = progressListenerCaptor.value
+ progressListener = progressProvider
}
@Test
@@ -81,7 +87,9 @@
underTest.statusViewCentered = true
val view = View(context)
- whenever(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
+ whenever(keyguardRootView.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(
+ view
+ )
progressListener.onTransitionStarted()
assertThat(view.translationX).isZero()
@@ -101,7 +109,9 @@
whenever(statusBarStateController.getState()).thenReturn(SHADE)
val view = View(context)
- whenever(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
+ whenever(keyguardRootView.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(
+ view
+ )
progressListener.onTransitionStarted()
assertThat(view.translationX).isZero()
@@ -121,7 +131,10 @@
whenever(statusBarStateController.getState()).thenReturn(KEYGUARD)
val view = View(context)
- whenever(parent.findViewById<View>(R.id.lockscreen_clock_view_large)).thenReturn(view)
+ whenever(
+ notificationShadeWindowView
+ .findViewById<View>(R.id.lockscreen_clock_view_large)
+ ).thenReturn(view)
progressListener.onTransitionStarted()
assertThat(view.translationX).isZero()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt
deleted file mode 100644
index 64bd742..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorImplTest.kt
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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.bluetooth.qsdialog
-
-import android.bluetooth.BluetoothDevice
-import android.testing.TestableLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.settingslib.bluetooth.CachedBluetoothDevice
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.whenever
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
-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.verify
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@OptIn(ExperimentalCoroutinesApi::class)
-class DeviceItemActionInteractorImplTest : SysuiTestCase() {
- @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
- private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
- private lateinit var actionInteractorImpl: DeviceItemActionInteractor
-
- @Mock private lateinit var dialog: SystemUIDialog
- @Mock private lateinit var cachedDevice: CachedBluetoothDevice
- @Mock private lateinit var device: BluetoothDevice
- @Mock private lateinit var deviceItem: DeviceItem
-
- @Before
- fun setUp() {
- actionInteractorImpl = kosmos.deviceItemActionInteractor
- whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedDevice)
- whenever(cachedDevice.address).thenReturn("ADDRESS")
- whenever(cachedDevice.device).thenReturn(device)
- }
-
- @Test
- fun testOnClick_connectedMedia_setActive() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type)
- .thenReturn(DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).setActive()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(
- cachedDevice.address,
- DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE
- )
- }
- }
- }
-
- @Test
- fun testOnClick_activeMedia_disconnect() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type).thenReturn(DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).disconnect()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(
- cachedDevice.address,
- DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE
- )
- }
- }
- }
-
- @Test
- fun testOnClick_connectedOtherDevice_disconnect() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).disconnect()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(cachedDevice.address, DeviceItemType.CONNECTED_BLUETOOTH_DEVICE)
- }
- }
- }
-
- @Test
- fun testOnClick_saved_connect() {
- with(kosmos) {
- testScope.runTest {
- whenever(deviceItem.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE)
- actionInteractorImpl.onClick(deviceItem, dialog)
- verify(cachedDevice).connect()
- verify(bluetoothTileDialogLogger)
- .logDeviceClick(cachedDevice.address, DeviceItemType.SAVED_BLUETOOTH_DEVICE)
- }
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
index e8e37bc..5ff4634 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorKosmos.kt
@@ -13,19 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.android.systemui.bluetooth.qsdialog
import com.android.internal.logging.uiEventLogger
+import com.android.settingslib.bluetooth.LocalBluetoothManager
+import com.android.systemui.animation.DialogTransitionAnimator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.plugins.activityStarter
import com.android.systemui.util.mockito.mock
val Kosmos.bluetoothTileDialogLogger: BluetoothTileDialogLogger by Kosmos.Fixture { mock {} }
+val Kosmos.localBluetoothManager: LocalBluetoothManager by Kosmos.Fixture { mock {} }
+
+val Kosmos.dialogTransitionAnimator: DialogTransitionAnimator by Kosmos.Fixture { mock {} }
+
val Kosmos.deviceItemActionInteractor: DeviceItemActionInteractor by
Kosmos.Fixture {
- DeviceItemActionInteractorImpl(
+ DeviceItemActionInteractor(
+ activityStarter,
+ dialogTransitionAnimator,
+ localBluetoothManager,
testDispatcher,
bluetoothTileDialogLogger,
uiEventLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
new file mode 100644
index 0000000..8246506
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemActionInteractorTest.kt
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.bluetooth.qsdialog
+
+import android.bluetooth.BluetoothDevice
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.settingslib.bluetooth.BluetoothUtils
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.LeAudioProfile
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.activityStarter
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@OptIn(ExperimentalCoroutinesApi::class)
+class DeviceItemActionInteractorTest : SysuiTestCase() {
+ @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ private val kosmos = testKosmos().apply { testDispatcher = UnconfinedTestDispatcher() }
+ private lateinit var actionInteractorImpl: DeviceItemActionInteractor
+ private lateinit var mockitoSession: StaticMockitoSession
+ private lateinit var activeMediaDeviceItem: DeviceItem
+ private lateinit var notConnectedDeviceItem: DeviceItem
+ private lateinit var connectedMediaDeviceItem: DeviceItem
+ private lateinit var connectedOtherDeviceItem: DeviceItem
+ @Mock private lateinit var dialog: SystemUIDialog
+ @Mock private lateinit var profileManager: LocalBluetoothProfileManager
+ @Mock private lateinit var leAudioProfile: LeAudioProfile
+ @Mock private lateinit var assistantProfile: LocalBluetoothLeBroadcastAssistant
+ @Mock private lateinit var bluetoothDevice: BluetoothDevice
+ @Mock private lateinit var bluetoothDeviceGroupId2: BluetoothDevice
+ @Mock private lateinit var cachedBluetoothDevice: CachedBluetoothDevice
+
+ @Before
+ fun setUp() {
+ mockitoSession =
+ mockitoSession().initMocks(this).mockStatic(BluetoothUtils::class.java).startMocking()
+ activeMediaDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ notConnectedDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.SAVED_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ connectedMediaDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ connectedOtherDeviceItem =
+ DeviceItem(
+ type = DeviceItemType.CONNECTED_BLUETOOTH_DEVICE,
+ cachedBluetoothDevice = cachedBluetoothDevice,
+ deviceName = DEVICE_NAME,
+ connectionSummary = DEVICE_CONNECTION_SUMMARY,
+ iconWithDescription = null,
+ background = null
+ )
+ actionInteractorImpl = kosmos.deviceItemActionInteractor
+ }
+
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ }
+
+ @Test
+ fun testOnClick_connectedMedia_setActive() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(cachedBluetoothDevice).setActive()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.AVAILABLE_MEDIA_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_activeMedia_disconnect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(activeMediaDeviceItem, dialog)
+ verify(cachedBluetoothDevice).disconnect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_connectedOtherDevice_disconnect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(connectedOtherDeviceItem, dialog)
+ verify(cachedBluetoothDevice).disconnect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.CONNECTED_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_saved_connect() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(cachedBluetoothDevice).connect()
+ verify(bluetoothTileDialogLogger)
+ .logDeviceClick(
+ cachedBluetoothDevice.address,
+ DeviceItemType.SAVED_BLUETOOTH_DEVICE
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_audioSharingDisabled_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(false)
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_inAudioSharing_clickedDeviceHasSource_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.connectableProfiles)
+ .thenReturn(listOf(leAudioProfile))
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
+ whenever(
+ BluetoothUtils.hasConnectedBroadcastSource(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.any()
+ )
+ )
+ .thenReturn(true)
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_inAudioSharing_clickedDeviceNoSource_shouldLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+ whenever(cachedBluetoothDevice.connectableProfiles)
+ .thenReturn(listOf(leAudioProfile))
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(BluetoothUtils.isBroadcasting(ArgumentMatchers.any())).thenReturn(true)
+ whenever(
+ BluetoothUtils.hasConnectedBroadcastSource(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.any()
+ )
+ )
+ .thenReturn(false)
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter)
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_noConnectedLeDevice_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasOneConnectedLeDevice_clickedNonLe_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice))
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasOneConnectedLeDevice_clickedLe_shouldLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.profiles).thenReturn(listOf(leAudioProfile))
+ whenever(leAudioProfile.isEnabled(ArgumentMatchers.any())).thenReturn(true)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice))
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter)
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasOneConnectedLeDevice_clickedConnectedLe_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice))
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasTwoConnectedLeDevice_clickedNotConnectedLe_shouldNotLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice, bluetoothDeviceGroupId2))
+ whenever(leAudioProfile.getGroupId(ArgumentMatchers.any())).thenAnswer {
+ val device = it.arguments.first() as BluetoothDevice
+ if (device == bluetoothDevice) GROUP_ID_1 else GROUP_ID_2
+ }
+
+ actionInteractorImpl.onClick(notConnectedDeviceItem, dialog)
+ verify(activityStarter, Mockito.never())
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOnClick_hasTwoConnectedLeDevice_clickedConnectedLe_shouldLaunchSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ whenever(cachedBluetoothDevice.device).thenReturn(bluetoothDevice)
+ whenever(cachedBluetoothDevice.address).thenReturn(DEVICE_ADDRESS)
+ whenever(cachedBluetoothDevice.profiles).thenReturn(listOf(leAudioProfile))
+ whenever(leAudioProfile.isEnabled(ArgumentMatchers.any())).thenReturn(true)
+
+ whenever(BluetoothUtils.isAudioSharingEnabled()).thenReturn(true)
+ whenever(localBluetoothManager.profileManager).thenReturn(profileManager)
+ whenever(profileManager.leAudioProfile).thenReturn(leAudioProfile)
+ whenever(profileManager.leAudioBroadcastAssistantProfile)
+ .thenReturn(assistantProfile)
+
+ whenever(
+ assistantProfile.getDevicesMatchingConnectionStates(ArgumentMatchers.any())
+ )
+ .thenReturn(listOf(bluetoothDevice, bluetoothDeviceGroupId2))
+ whenever(leAudioProfile.getGroupId(ArgumentMatchers.any())).thenAnswer {
+ val device = it.arguments.first() as BluetoothDevice
+ if (device == bluetoothDevice) GROUP_ID_1 else GROUP_ID_2
+ }
+
+ actionInteractorImpl.onClick(connectedMediaDeviceItem, dialog)
+ verify(activityStarter)
+ .postStartActivityDismissingKeyguard(
+ ArgumentMatchers.any(),
+ ArgumentMatchers.anyInt(),
+ ArgumentMatchers.any()
+ )
+ }
+ }
+ }
+
+ private companion object {
+ const val DEVICE_NAME = "device"
+ const val DEVICE_CONNECTION_SUMMARY = "active"
+ const val DEVICE_ADDRESS = "address"
+ const val GROUP_ID_1 = 1
+ const val GROUP_ID_2 = 2
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index e02fb29..89e0971 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -30,7 +30,6 @@
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
import com.android.systemui.dock.fakeDockManager
import com.android.systemui.flags.BrokenWithSceneContainer
import com.android.systemui.flags.DisableSceneContainer
@@ -608,31 +607,6 @@
/** This handles security method NONE and screen off with lock timeout */
@Test
- fun dozingToGoneWithKeyguardNotShowing() =
- testScope.runTest {
- // GIVEN a prior transition has run to DOZING
- runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
- runCurrent()
-
- // WHEN the device wakes up without a keyguard
- keyguardRepository.setKeyguardShowing(false)
- keyguardRepository.setKeyguardDismissible(true)
- kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(false)
- powerInteractor.setAwakeForTest()
- advanceTimeBy(60L)
-
- assertThat(transitionRepository)
- .startedTransition(
- to = KeyguardState.GONE,
- from = KeyguardState.DOZING,
- animatorAssertion = { it.isNotNull() }
- )
-
- coroutineContext.cancelChildren()
- }
-
- /** This handles security method NONE and screen off with lock timeout */
- @Test
@DisableSceneContainer
fun dreamingToGoneWithKeyguardNotShowing() =
testScope.runTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index ec02c64..411ff91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -113,8 +113,8 @@
LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED);
mMediaDevices.add(mMediaDevice1);
mMediaDevices.add(mMediaDevice2);
- mMediaItems.add(new MediaItem(mMediaDevice1));
- mMediaItems.add(new MediaItem(mMediaDevice2));
+ mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice1));
+ mMediaItems.add(MediaItem.createDeviceMediaItem(mMediaDevice2));
mMediaOutputAdapter = new MediaOutputAdapter(mMediaOutputController);
mMediaOutputAdapter.updateItems();
@@ -146,7 +146,8 @@
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
- mMediaItems.add(new MediaItem());
+ mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
+ mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
mMediaOutputAdapter.updateItems();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
@@ -589,7 +590,7 @@
mMediaOutputAdapter.updateItems();
mViewHolder = (MediaOutputAdapter.MediaDeviceViewHolder) mMediaOutputAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
- mMediaItems.add(new MediaItem());
+ mMediaItems.add(MediaItem.createPairNewDeviceMediaItem());
mMediaOutputAdapter.updateItems();
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 2);
mViewHolder.mContainerLayout.performClick();
@@ -725,7 +726,7 @@
public void updateItems_controllerItemsUpdated_notUpdatesInAdapterUntilUpdateItems() {
mMediaOutputAdapter.updateItems();
List<MediaItem> updatedList = new ArrayList<>();
- updatedList.add(new MediaItem());
+ updatedList.add(MediaItem.createPairNewDeviceMediaItem());
when(mMediaOutputController.getMediaItemList()).thenReturn(updatedList);
assertThat(mMediaOutputAdapter.getItemCount()).isEqualTo(mMediaItems.size());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
index b7fefc0..c0d411b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -16,7 +16,9 @@
package com.android.systemui.mediaprojection.data.repository
+import android.media.projection.MediaProjectionInfo
import android.os.Binder
+import android.os.UserHandle
import android.view.ContentRecordingSession
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -26,6 +28,7 @@
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createToken
+import com.android.systemui.mediaprojection.taskswitcher.FakeMediaProjectionManager.Companion.createDisplaySession
import com.android.systemui.mediaprojection.taskswitcher.fakeActivityTaskManager
import com.android.systemui.mediaprojection.taskswitcher.fakeMediaProjectionManager
import com.android.systemui.mediaprojection.taskswitcher.taskSwitcherKosmos
@@ -33,6 +36,7 @@
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
@SmallTest
@@ -55,7 +59,8 @@
fakeActivityTaskManager.addRunningTasks(task)
repo.switchProjectedTask(task)
- assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.SingleTask::class.java)
+ assertThat((state as MediaProjectionState.Projecting.SingleTask).task).isEqualTo(task)
}
@Test
@@ -97,7 +102,7 @@
session = ContentRecordingSession.createDisplaySession(/* displayToMirror= */ 123)
)
- assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.EntireScreen::class.java)
}
@Test
@@ -110,7 +115,27 @@
session = ContentRecordingSession.createTaskSession(taskWindowContainerToken)
)
- assertThat(state).isEqualTo(MediaProjectionState.EntireScreen)
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.EntireScreen::class.java)
+ }
+
+ @Test
+ fun mediaProjectionState_entireScreen_hasHostPackage() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+
+ val info =
+ MediaProjectionInfo(
+ /* packageName= */ "com.media.projection.repository.test",
+ /* handle= */ UserHandle.getUserHandleForUid(UserHandle.myUserId()),
+ /* launchCookie = */ null,
+ )
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ info = info,
+ session = createDisplaySession(),
+ )
+
+ assertThat((state as MediaProjectionState.Projecting.EntireScreen).hostPackage)
+ .isEqualTo("com.media.projection.repository.test")
}
@Test
@@ -125,6 +150,39 @@
session = ContentRecordingSession.createTaskSession(token.asBinder())
)
- assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
+ assertThat(state).isInstanceOf(MediaProjectionState.Projecting.SingleTask::class.java)
+ assertThat((state as MediaProjectionState.Projecting.SingleTask).task).isEqualTo(task)
+ }
+
+ @Test
+ fun mediaProjectionState_singleTask_hasHostPackage() =
+ testScope.runTest {
+ val state by collectLastValue(repo.mediaProjectionState)
+
+ val token = createToken()
+ val task = createTask(taskId = 1, token = token)
+ fakeActivityTaskManager.addRunningTasks(task)
+
+ val info =
+ MediaProjectionInfo(
+ /* packageName= */ "com.media.projection.repository.test",
+ /* handle= */ UserHandle.getUserHandleForUid(UserHandle.myUserId()),
+ /* launchCookie = */ null,
+ )
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ info = info,
+ session = ContentRecordingSession.createTaskSession(token.asBinder())
+ )
+
+ assertThat((state as MediaProjectionState.Projecting.SingleTask).hostPackage)
+ .isEqualTo("com.media.projection.repository.test")
+ }
+
+ @Test
+ fun stopProjecting_invokesManager() =
+ testScope.runTest {
+ repo.stopProjecting()
+
+ verify(fakeMediaProjectionManager.mediaProjectionManager).stopActiveProjection()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
index b77a15b..61ea437 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
@@ -119,4 +119,12 @@
assertThat(lastModel).isEqualTo(isRecording)
}
+
+ @Test
+ fun stopRecording_invokesController() =
+ testScope.runTest {
+ underTest.stopRecording()
+
+ verify(recordingController).stopRecording()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 586adbd..74a2999 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -70,6 +70,7 @@
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
+import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
@@ -85,6 +86,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Answers
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.anyFloat
@@ -132,6 +134,8 @@
private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
@Mock private lateinit var mGlanceableHubContainerController: GlanceableHubContainerController
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private lateinit var sysUiUnfoldComponent: SysUIUnfoldComponent
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@@ -209,6 +213,7 @@
dozeScrimController,
notificationShadeWindowController,
unfoldTransitionProgressProvider,
+ Optional.of(sysUiUnfoldComponent),
keyguardUnlockAnimationController,
notificationInsetsController,
ambientState,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index e83a46b..31bd12f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -58,6 +58,7 @@
import com.android.systemui.statusbar.phone.DozeServiceHost
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.window.StatusBarWindowStateController
+import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
@@ -112,6 +113,7 @@
@Mock private lateinit var shadeLogger: ShadeLogger
@Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var pulsingGestureListener: PulsingGestureListener
+ @Mock private lateinit var sysUiUnfoldComponent: SysUIUnfoldComponent
@Mock
private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener
@Mock private lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@@ -181,6 +183,7 @@
dozeScrimController,
notificationShadeWindowController,
unfoldTransitionProgressProvider,
+ Optional.of(sysUiUnfoldComponent),
keyguardUnlockAnimationController,
notificationInsetsController,
ambientState,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
index a05a23b..293dc04 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
@@ -27,6 +27,9 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
@@ -78,6 +81,22 @@
}
@Test
+ fun initMultipleTimes_onTransition_translationIsSetOnlyOnce() {
+ animator.init(parent, MAX_TRANSLATION)
+ animator.init(parent, MAX_TRANSLATION)
+ animator.init(parent, MAX_TRANSLATION)
+
+ // GIVEN one view with a matching id
+ val view = spy(View(context))
+ whenever(parent.findViewById<View>(START_VIEW_ID)).thenReturn(view)
+ progressProvider.onTransitionStarted()
+
+ // WHEN the transition progresses, translation is updated once
+ progressProvider.onTransitionProgress(.5f)
+ verify(view).translationX = anyFloat()
+ }
+
+ @Test
fun onTransition_oneMovesStartWithRTL() {
// GIVEN one view with a matching id
val view = View(context)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractorTest.kt
new file mode 100644
index 0000000..abb6e2b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractorTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.domain.interactor
+
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.DialogTransitionAnimator
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor.Companion.createDialogLaunchOnClickListener
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import kotlin.test.Test
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+class OngoingActivityChipInteractorTest : SysuiTestCase() {
+ private val mockSystemUIDialog = mock<SystemUIDialog>()
+ private val dialogDelegate = SystemUIDialog.Delegate { mockSystemUIDialog }
+ private val dialogTransitionAnimator = mock<DialogTransitionAnimator>()
+
+ private val chipBackgroundView = mock<ChipBackgroundContainer>()
+ private val chipView =
+ mock<View>().apply {
+ whenever(
+ this.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ )
+ .thenReturn(chipBackgroundView)
+ }
+
+ @Test
+ fun createDialogLaunchOnClickListener_showsDialogOnClick() {
+ val clickListener =
+ createDialogLaunchOnClickListener(dialogDelegate, dialogTransitionAnimator)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(dialogTransitionAnimator)
+ .showFromView(
+ eq(mockSystemUIDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
index 0f33b9d..a4505a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorTest.kt
@@ -16,8 +16,15 @@
package com.android.systemui.statusbar.chips.mediaprojection.domain.interactor
+import android.Manifest
+import android.content.Intent
+import android.content.packageManager
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.mockDialogTransitionAnimator
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
@@ -27,11 +34,24 @@
import com.android.systemui.mediaprojection.taskswitcher.FakeActivityTaskManager.Companion.createTask
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
-import com.android.systemui.statusbar.chips.ui.viewmodel.mediaProjectionChipInteractor
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndCastToOtherDeviceDialogDelegate
+import com.android.systemui.statusbar.chips.mediaprojection.ui.view.EndShareToAppDialogDelegate
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.doAnswer
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
@SmallTest
class MediaProjectionChipInteractorTest : SysuiTestCase() {
@@ -40,6 +60,30 @@
private val mediaProjectionRepo = kosmos.fakeMediaProjectionRepository
private val systemClock = kosmos.fakeSystemClock
+ private val mockCastDialog = mock<SystemUIDialog>()
+ private val mockShareDialog = mock<SystemUIDialog>()
+
+ private val chipBackgroundView = mock<ChipBackgroundContainer>()
+ private val chipView =
+ mock<View>().apply {
+ whenever(
+ this.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ )
+ .thenReturn(chipBackgroundView)
+ }
+
+ @Before
+ fun setUp() {
+ setUpPackageManagerForMediaProjection(kosmos)
+
+ whenever(kosmos.mockSystemUIDialogFactory.create(any<EndCastToOtherDeviceDialogDelegate>()))
+ .thenReturn(mockCastDialog)
+ whenever(kosmos.mockSystemUIDialogFactory.create(any<EndShareToAppDialogDelegate>()))
+ .thenReturn(mockShareDialog)
+ }
+
private val underTest = kosmos.mediaProjectionChipInteractor
@Test
@@ -53,12 +97,15 @@
}
@Test
- fun chip_singleTaskState_isShownWithIcon() =
+ fun chip_singleTaskState_otherDevicesPackage_castToOtherDeviceChipShown() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
mediaProjectionRepo.mediaProjectionState.value =
- MediaProjectionState.SingleTask(createTask(taskId = 1))
+ MediaProjectionState.Projecting.SingleTask(
+ CAST_TO_OTHER_DEVICES_PACKAGE,
+ createTask(taskId = 1)
+ )
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
@@ -66,11 +113,12 @@
}
@Test
- fun chip_entireScreenState_isShownWithIcon() =
+ fun chip_entireScreenState_otherDevicesPackage_castToOtherDeviceChipShown() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
- mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE)
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
@@ -78,12 +126,39 @@
}
@Test
+ fun chip_singleTaskState_normalPackage_shareToAppChipShown() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.SingleTask(NORMAL_PACKAGE, createTask(taskId = 1))
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenshot_share)
+ }
+
+ @Test
+ fun chip_entireScreenState_normalPackage_shareToAppChipShown() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
+
+ assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
+ val icon = (latest as OngoingActivityChipModel.Shown).icon
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenshot_share)
+ }
+
+ @Test
fun chip_timeResetsOnEachNewShare() =
testScope.runTest {
val latest by collectLastValue(underTest.chip)
systemClock.setElapsedRealtime(1234)
- mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(1234)
@@ -92,9 +167,99 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Hidden::class.java)
systemClock.setElapsedRealtime(5678)
- mediaProjectionRepo.mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.SingleTask(
+ CAST_TO_OTHER_DEVICES_PACKAGE,
+ createTask(taskId = 1)
+ )
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(5678)
}
+
+ @Test
+ fun chip_castToOtherDevice_clickListenerShowsCastDialog() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(CAST_TO_OTHER_DEVICES_PACKAGE)
+
+ val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(kosmos.mockDialogTransitionAnimator)
+ .showFromView(
+ eq(mockCastDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
+
+ @Test
+ fun chip_shareToApp_clickListenerShowsShareDialog() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+ mediaProjectionRepo.mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
+
+ val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(kosmos.mockDialogTransitionAnimator)
+ .showFromView(
+ eq(mockShareDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
+
+ companion object {
+ const val CAST_TO_OTHER_DEVICES_PACKAGE = "other.devices.package"
+ const val NORMAL_PACKAGE = "some.normal.package"
+
+ /**
+ * Sets up [kosmos.packageManager] so that [CAST_TO_OTHER_DEVICES_PACKAGE] is marked as a
+ * package that casts to other devices, and [NORMAL_PACKAGE] is *not* marked as casting to
+ * other devices.
+ */
+ fun setUpPackageManagerForMediaProjection(kosmos: Kosmos) {
+ kosmos.packageManager.apply {
+ whenever(
+ this.checkPermission(
+ Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+ CAST_TO_OTHER_DEVICES_PACKAGE
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_GRANTED)
+ whenever(
+ this.checkPermission(
+ Manifest.permission.REMOTE_DISPLAY_PROVIDER,
+ NORMAL_PACKAGE
+ )
+ )
+ .thenReturn(PackageManager.PERMISSION_DENIED)
+
+ doAnswer {
+ // See Utils.isHeadlessRemoteDisplayProvider
+ if (
+ (it.arguments[0] as Intent).`package` == CAST_TO_OTHER_DEVICES_PACKAGE
+ ) {
+ emptyList()
+ } else {
+ listOf(mock<ResolveInfo>())
+ }
+ }
+ .whenever(this)
+ .queryIntentActivities(any(), anyInt())
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegateTest.kt
new file mode 100644
index 0000000..9a2f545
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndCastToOtherDeviceDialogDelegateTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.mediaprojection.ui.view
+
+import android.content.DialogInterface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class EndCastToOtherDeviceDialogDelegateTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val sysuiDialog = mock<SystemUIDialog>()
+ private val sysuiDialogFactory = kosmos.mockSystemUIDialogFactory
+ private val underTest =
+ EndCastToOtherDeviceDialogDelegate(
+ sysuiDialogFactory,
+ kosmos.mediaProjectionChipInteractor,
+ )
+
+ @Before
+ fun setUp() {
+ whenever(sysuiDialogFactory.create(eq(underTest), eq(context))).thenReturn(sysuiDialog)
+ }
+
+ @Test
+ fun icon() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setIcon(R.drawable.ic_cast_connected)
+ }
+
+ @Test
+ fun title() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setTitle(R.string.cast_to_other_device_stop_dialog_title)
+ }
+
+ @Test
+ fun message() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setMessage(R.string.cast_to_other_device_stop_dialog_message)
+ }
+
+ @Test
+ fun negativeButton() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setNegativeButton(R.string.close_dialog_button, null)
+ }
+
+ @Test
+ fun positiveButton() =
+ kosmos.testScope.runTest {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ val clickListener = argumentCaptor<DialogInterface.OnClickListener>()
+
+ // Verify the button has the right text
+ verify(sysuiDialog)
+ .setPositiveButton(
+ eq(R.string.cast_to_other_device_stop_dialog_button),
+ clickListener.capture()
+ )
+
+ // Verify that clicking the button stops the recording
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isFalse()
+
+ clickListener.firstValue.onClick(mock<DialogInterface>(), 0)
+ runCurrent()
+
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegateTest.kt
new file mode 100644
index 0000000..1d6e866
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/mediaprojection/ui/view/EndShareToAppDialogDelegateTest.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.mediaprojection.ui.view
+
+import android.content.DialogInterface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class EndShareToAppDialogDelegateTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val sysuiDialog = mock<SystemUIDialog>()
+ private val sysuiDialogFactory = kosmos.mockSystemUIDialogFactory
+ private val underTest =
+ EndShareToAppDialogDelegate(
+ sysuiDialogFactory,
+ kosmos.mediaProjectionChipInteractor,
+ )
+
+ @Before
+ fun setUp() {
+ whenever(sysuiDialogFactory.create(eq(underTest), eq(context))).thenReturn(sysuiDialog)
+ }
+
+ @Test
+ fun icon() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setIcon(R.drawable.ic_screenshot_share)
+ }
+
+ @Test
+ fun title() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setTitle(R.string.share_to_app_stop_dialog_title)
+ }
+
+ @Test
+ fun message() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setMessage(R.string.share_to_app_stop_dialog_message)
+ }
+
+ @Test
+ fun negativeButton() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setNegativeButton(R.string.close_dialog_button, null)
+ }
+
+ @Test
+ fun positiveButton() =
+ kosmos.testScope.runTest {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ val clickListener = argumentCaptor<DialogInterface.OnClickListener>()
+
+ // Verify the button has the right text
+ verify(sysuiDialog)
+ .setPositiveButton(
+ eq(R.string.share_to_app_stop_dialog_button),
+ clickListener.capture()
+ )
+
+ // Verify that clicking the button stops the recording
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isFalse()
+
+ clickListener.firstValue.onClick(mock<DialogInterface>(), 0)
+ runCurrent()
+
+ assertThat(kosmos.fakeMediaProjectionRepository.stopProjectingInvoked).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
index 25efaf1..f6c3adb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractorTest.kt
@@ -16,8 +16,10 @@
package com.android.systemui.statusbar.chips.screenrecord.domain.interactor
+import android.view.View
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.mockDialogTransitionAnimator
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.Kosmos
@@ -26,11 +28,21 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
import com.android.systemui.statusbar.chips.ui.viewmodel.screenRecordChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
import com.android.systemui.util.time.fakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
@SmallTest
class ScreenRecordChipInteractorTest : SysuiTestCase() {
@@ -38,9 +50,27 @@
private val testScope = kosmos.testScope
private val screenRecordRepo = kosmos.screenRecordRepository
private val systemClock = kosmos.fakeSystemClock
+ private val mockSystemUIDialog = mock<SystemUIDialog>()
+
+ private val chipBackgroundView = mock<ChipBackgroundContainer>()
+ private val chipView =
+ mock<View>().apply {
+ whenever(
+ this.requireViewById<ChipBackgroundContainer>(
+ R.id.ongoing_activity_chip_background
+ )
+ )
+ .thenReturn(chipBackgroundView)
+ }
private val underTest = kosmos.screenRecordChipInteractor
+ @Before
+ fun setUp() {
+ whenever(kosmos.mockSystemUIDialogFactory.create(any<SystemUIDialog.Delegate>()))
+ .thenReturn(mockSystemUIDialog)
+ }
+
@Test
fun chip_doingNothingState_isHidden() =
testScope.runTest {
@@ -70,7 +100,7 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
- assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record)
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenrecord)
}
@Test
@@ -93,4 +123,25 @@
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
assertThat((latest as OngoingActivityChipModel.Shown).startTimeMs).isEqualTo(5678)
}
+
+ @Test
+ fun chip_clickListenerShowsDialog() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.chip)
+ screenRecordRepo.screenRecordState.value = ScreenRecordModel.Recording
+
+ val clickListener = ((latest as OngoingActivityChipModel.Shown).onClickListener)
+
+ // Dialogs must be created on the main thread
+ context.mainExecutor.execute {
+ clickListener.onClick(chipView)
+ verify(kosmos.mockDialogTransitionAnimator)
+ .showFromView(
+ eq(mockSystemUIDialog),
+ eq(chipBackgroundView),
+ eq(null),
+ anyBoolean(),
+ )
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt
new file mode 100644
index 0000000..bca6763
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/screenrecord/ui/view/EndScreenRecordingDialogDelegateTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.screenrecord.ui.view
+
+import android.content.DialogInterface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.statusbar.chips.ui.viewmodel.screenRecordChipInteractor
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+class EndScreenRecordingDialogDelegateTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+
+ private val sysuiDialog = mock<SystemUIDialog>()
+ private val sysuiDialogFactory = kosmos.mockSystemUIDialogFactory
+
+ private val underTest =
+ EndScreenRecordingDialogDelegate(
+ sysuiDialogFactory,
+ kosmos.screenRecordChipInteractor,
+ )
+
+ @Before
+ fun setUp() {
+ whenever(sysuiDialogFactory.create(eq(underTest), eq(context))).thenReturn(sysuiDialog)
+ }
+
+ @Test
+ fun icon() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setIcon(R.drawable.ic_screenrecord)
+ }
+
+ @Test
+ fun title() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setTitle(R.string.screenrecord_stop_dialog_title)
+ }
+
+ @Test
+ fun message() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setMessage(R.string.screenrecord_stop_dialog_message)
+ }
+
+ @Test
+ fun negativeButton() {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ verify(sysuiDialog).setNegativeButton(R.string.close_dialog_button, null)
+ }
+
+ @Test
+ fun positiveButton() =
+ kosmos.testScope.runTest {
+ underTest.beforeCreate(sysuiDialog, /* savedInstanceState= */ null)
+
+ val clickListener = argumentCaptor<DialogInterface.OnClickListener>()
+
+ // Verify the button has the right text
+ verify(sysuiDialog)
+ .setPositiveButton(
+ eq(R.string.screenrecord_stop_dialog_button),
+ clickListener.capture()
+ )
+
+ // Verify that clicking the button stops the recording
+ assertThat(kosmos.screenRecordRepository.stopRecordingInvoked).isFalse()
+
+ clickListener.firstValue.onClick(mock<DialogInterface>(), 0)
+ runCurrent()
+
+ assertThat(kosmos.screenRecordRepository.stopRecordingInvoked).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 121229c..6712963 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -30,8 +30,11 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
@SmallTest
@@ -46,6 +49,11 @@
private val underTest = kosmos.ongoingActivityChipsViewModel
+ @Before
+ fun setUp() {
+ setUpPackageManagerForMediaProjection(kosmos)
+ }
+
@Test
fun chip_allHidden_hidden() =
testScope.runTest {
@@ -91,7 +99,8 @@
fun chip_screenRecordShowAndMediaProjectionShow_screenRecordShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.Recording
- mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
callState.value = OngoingActivityChipModel.Hidden
val latest by collectLastValue(underTest.chip)
@@ -103,7 +112,8 @@
fun chip_mediaProjectionShowAndCallShow_mediaProjectionShown() =
testScope.runTest {
screenRecordState.value = ScreenRecordModel.DoingNothing
- mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
val callChip =
OngoingActivityChipModel.Shown(
Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
@@ -113,7 +123,7 @@
val latest by collectLastValue(underTest.chip)
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
}
@Test
@@ -152,10 +162,14 @@
assertThat(latest).isEqualTo(callChip)
// WHEN the higher priority media projection chip is added
- mediaProjectionState.value = MediaProjectionState.SingleTask(createTask(taskId = 1))
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.SingleTask(
+ NORMAL_PACKAGE,
+ createTask(taskId = 1),
+ )
// THEN the higher priority media projection chip is used
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
// WHEN the higher priority screen record chip is added
screenRecordState.value = ScreenRecordModel.Recording
@@ -169,7 +183,8 @@
testScope.runTest {
// WHEN all chips are active
screenRecordState.value = ScreenRecordModel.Recording
- mediaProjectionState.value = MediaProjectionState.EntireScreen
+ mediaProjectionState.value =
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
val callChip =
OngoingActivityChipModel.Shown(
@@ -187,7 +202,7 @@
screenRecordState.value = ScreenRecordModel.DoingNothing
// THEN the lower priority media projection is used
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
// WHEN the higher priority media projection is removed
mediaProjectionState.value = MediaProjectionState.NotProjecting
@@ -200,13 +215,13 @@
fun assertIsScreenRecordChip(latest: OngoingActivityChipModel?) {
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
- assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.stat_sys_screen_record)
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenrecord)
}
- fun assertIsMediaProjectionChip(latest: OngoingActivityChipModel?) {
+ fun assertIsShareToAppChip(latest: OngoingActivityChipModel?) {
assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java)
val icon = (latest as OngoingActivityChipModel.Shown).icon
- assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_cast_connected)
+ assertThat((icon as Icon.Resource).res).isEqualTo(R.drawable.ic_screenshot_share)
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index f3d6407..53e643e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -223,7 +223,8 @@
mFakeExecutor,
mBackgroundExecutor,
mLogger,
- mStatusOverlayHoverListenerFactory
+ mStatusOverlayHoverListenerFactory,
+ mKosmos.getCommunalSceneInteractor()
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index c9fe449..cdb2b88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -37,8 +37,10 @@
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.domain.model.OngoingActivityChipModel
-import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsMediaProjectionChip
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip
import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
import com.android.systemui.statusbar.data.model.StatusBarMode
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
@@ -55,6 +57,7 @@
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
@SmallTest
@@ -77,6 +80,11 @@
kosmos.applicationCoroutineScope,
)
+ @Before
+ fun setUp() {
+ setUpPackageManagerForMediaProjection(kosmos)
+ }
+
@Test
fun isTransitioningFromLockscreenToOccluded_started_isTrue() =
testScope.runTest {
@@ -405,9 +413,9 @@
assertThat(latest).isEqualTo(OngoingActivityChipModel.Hidden)
kosmos.fakeMediaProjectionRepository.mediaProjectionState.value =
- MediaProjectionState.EntireScreen
+ MediaProjectionState.Projecting.EntireScreen(NORMAL_PACKAGE)
- assertIsMediaProjectionChip(latest)
+ assertIsShareToAppChip(latest)
}
private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
index 62e56be..976a19c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/DialogTransitionAnimatorKosmos.kt
@@ -20,6 +20,7 @@
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.util.mockito.mock
val Kosmos.dialogTransitionAnimator by Fixture {
fakeDialogTransitionAnimator(
@@ -29,3 +30,5 @@
interactionJankMonitor = interactionJankMonitor,
)
}
+
+val Kosmos.mockDialogTransitionAnimator by Fixture { mock<DialogTransitionAnimator>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
index 02842cc..b5ca964 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorFactory.kt
@@ -24,6 +24,7 @@
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.scene.domain.interactor.SceneInteractor
@@ -34,6 +35,7 @@
import com.android.systemui.util.mockito.whenever
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
/**
@@ -60,9 +62,11 @@
): WithDependencies {
// Mock these until they are replaced by kosmos
val currentKeyguardStateFlow = MutableSharedFlow<KeyguardState>()
+ val transitionStateFlow = MutableStateFlow(TransitionStep())
val keyguardTransitionInteractor =
mock<KeyguardTransitionInteractor>().also {
whenever(it.currentKeyguardState).thenReturn(currentKeyguardStateFlow)
+ whenever(it.transitionState).thenReturn(transitionStateFlow)
}
val configurationDimensionFlow = MutableSharedFlow<ConfigurationBasedDimensions>()
configurationDimensionFlow.tryEmit(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
index 6d46694..3c62b44 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
@@ -22,6 +22,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.ui.systemBarUtilsProxy
@@ -30,6 +31,7 @@
KeyguardClockViewModel(
keyguardClockInteractor = keyguardClockInteractor,
applicationScope = applicationCoroutineScope,
+ aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
notifsKeyguardInteractor = notificationsKeyguardInteractor,
shadeInteractor = shadeInteractor,
systemBarUtils = systemBarUtilsProxy,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 45a14ad..67f8443 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -29,6 +29,7 @@
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.ui.viewmodel.communalTransitionViewModel
import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -113,6 +114,7 @@
val deviceEntryUdfpsInteractor by lazy { kosmos.deviceEntryUdfpsInteractor }
val deviceUnlockedInteractor by lazy { kosmos.deviceUnlockedInteractor }
val communalInteractor by lazy { kosmos.communalInteractor }
+ val communalSceneInteractor by lazy { kosmos.communalSceneInteractor }
val sceneContainerPlugin by lazy { kosmos.sceneContainerPlugin }
val deviceProvisioningInteractor by lazy { kosmos.deviceProvisioningInteractor }
val fakeDeviceProvisioningRepository by lazy { kosmos.fakeDeviceProvisioningRepository }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
index c4365c9..d631f92 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/data/repository/FakeMediaProjectionRepository.kt
@@ -25,4 +25,10 @@
override val mediaProjectionState: MutableStateFlow<MediaProjectionState> =
MutableStateFlow(MediaProjectionState.NotProjecting)
+
+ var stopProjectingInvoked = false
+
+ override suspend fun stopProjecting() {
+ stopProjectingInvoked = true
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
index d82286f..cf18c0e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt
@@ -26,6 +26,7 @@
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.testScope
@@ -67,5 +68,6 @@
uiEventLogger = uiEventLogger,
sceneBackInteractor = sceneBackInteractor,
shadeSessionStorage = shadeSessionStorage,
+ windowMgrLockscreenVisInteractor = windowManagerLockscreenVisibilityInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
index fb0e368..30b4763 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
@@ -22,4 +22,10 @@
class FakeScreenRecordRepository : ScreenRecordRepository {
override val screenRecordState: MutableStateFlow<ScreenRecordModel> =
MutableStateFlow(ScreenRecordModel.DoingNothing)
+
+ var stopRecordingInvoked = false
+
+ override suspend fun stopRecording() {
+ stopRecordingInvoked = true
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt
index 8d653f7..0e21698 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt
@@ -21,6 +21,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.plugins.activityStarter
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.privacyChipInteractor
import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
@@ -33,6 +34,7 @@
applicationScope = applicationCoroutineScope,
context = applicationContext,
activityStarter = activityStarter,
+ sceneInteractor = sceneInteractor,
shadeInteractor = shadeInteractor,
mobileIconsInteractor = mobileIconsInteractor,
mobileIconsViewModel = mobileIconsViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorKosmos.kt
new file mode 100644
index 0000000..062b448
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/mediaprojection/domain/interactor/MediaProjectionChipInteractorKosmos.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.chips.mediaprojection.domain.interactor
+
+import android.content.packageManager
+import com.android.systemui.animation.mockDialogTransitionAnimator
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
+import com.android.systemui.util.time.fakeSystemClock
+
+val Kosmos.mediaProjectionChipInteractor: MediaProjectionChipInteractor by
+ Kosmos.Fixture {
+ MediaProjectionChipInteractor(
+ scope = applicationCoroutineScope,
+ mediaProjectionRepository = fakeMediaProjectionRepository,
+ packageManager = packageManager,
+ systemClock = fakeSystemClock,
+ dialogFactory = mockSystemUIDialogFactory,
+ dialogTransitionAnimator = mockDialogTransitionAnimator,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
index 88bde2e..51ec540 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -16,13 +16,14 @@
package com.android.systemui.statusbar.chips.ui.viewmodel
+import com.android.systemui.animation.mockDialogTransitionAnimator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
-import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
-import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractor
+import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.mediaProjectionChipInteractor
import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory
import com.android.systemui.util.time.fakeSystemClock
val Kosmos.screenRecordChipInteractor: ScreenRecordChipInteractor by
@@ -30,15 +31,8 @@
ScreenRecordChipInteractor(
scope = applicationCoroutineScope,
screenRecordRepository = screenRecordRepository,
- systemClock = fakeSystemClock,
- )
- }
-
-val Kosmos.mediaProjectionChipInteractor: MediaProjectionChipInteractor by
- Kosmos.Fixture {
- MediaProjectionChipInteractor(
- scope = applicationCoroutineScope,
- mediaProjectionRepository = fakeMediaProjectionRepository,
+ dialogFactory = mockSystemUIDialogFactory,
+ dialogTransitionAnimator = mockDialogTransitionAnimator,
systemClock = fakeSystemClock,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index d00eedf..299486f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -31,6 +31,7 @@
import com.android.systemui.keyguard.ui.viewmodel.goneToAodTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.goneToDozingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.goneToDreamingTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.goneToLockscreenTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToDreamingTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGoneTransitionViewModel
@@ -70,6 +71,7 @@
goneToAodTransitionViewModel = goneToAodTransitionViewModel,
goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
goneToDreamingTransitionViewModel = goneToDreamingTransitionViewModel,
+ goneToLockscreenTransitionViewModel = goneToLockscreenTransitionViewModel,
glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel,
lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt
index 3bb9580..1851c89 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt
@@ -21,8 +21,9 @@
import com.android.systemui.broadcast.broadcastDispatcher
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.model.sysUiState
+import com.android.systemui.util.mockito.mock
-val Kosmos.systemUIDialogFactory by
+val Kosmos.systemUIDialogFactory: SystemUIDialogFactory by
Kosmos.Fixture {
SystemUIDialogFactory(
applicationContext,
@@ -32,3 +33,6 @@
dialogTransitionAnimator,
)
}
+
+val Kosmos.mockSystemUIDialogFactory: SystemUIDialog.Factory by
+ Kosmos.Fixture { mock<SystemUIDialog.Factory>() }
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/NaturalRotation.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/NaturalRotation.kt
new file mode 100644
index 0000000..be02487
--- /dev/null
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/NaturalRotation.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 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.unfold.dagger
+
+import javax.inject.Qualifier
+
+/** Qualifier annotation for a progress provider that emits animation events only when
+ * in natural rotation */
+@Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class NaturalRotation
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index c9cce15..0ab6bbc 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -532,7 +532,8 @@
String packageName, int userId) {
startObservingDevicePresence_enforcePermission();
- mDevicePresenceProcessor.startObservingDevicePresence(request, packageName, userId);
+ mDevicePresenceProcessor.startObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ true);
}
@Override
@@ -541,7 +542,8 @@
String packageName, int userId) {
stopObservingDevicePresence_enforcePermission();
- mDevicePresenceProcessor.stopObservingDevicePresence(request, packageName, userId);
+ mDevicePresenceProcessor.stopObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ true);
}
@Override
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index c892b84..3d53deb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -21,6 +21,7 @@
import android.companion.AssociationInfo;
import android.companion.ContextSyncMessage;
import android.companion.Flags;
+import android.companion.ObservingDevicePresenceRequest;
import android.companion.Telecom;
import android.companion.datatransfer.PermissionSyncRequest;
import android.net.MacAddress;
@@ -193,6 +194,43 @@
break;
}
+ case "start-observing-device-presence-uuid": {
+ if (Flags.devicePresence()) {
+ int userId = getNextIntArgRequired();
+ String packageName = getNextArgRequired();
+ String uuid = getNextArgRequired();
+ if ("null".equals(uuid)) {
+ out.println("UUID can not be null.");
+ break;
+ }
+ ParcelUuid parcelUuid = ParcelUuid.fromString(uuid);
+ ObservingDevicePresenceRequest request = new ObservingDevicePresenceRequest
+ .Builder().setUuid(parcelUuid).build();
+ mDevicePresenceProcessor.startObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ false);
+
+ }
+ break;
+ }
+
+ case "stop-observing-device-presence-uuid": {
+ if (Flags.devicePresence()) {
+ int userId = getNextIntArgRequired();
+ String packageName = getNextArgRequired();
+ String uuid = getNextArgRequired();
+ if ("null".equals(uuid)) {
+ out.println("UUID can not be null.");
+ break;
+ }
+ ParcelUuid parcelUuid = ParcelUuid.fromString(uuid);
+ ObservingDevicePresenceRequest request = new ObservingDevicePresenceRequest
+ .Builder().setUuid(parcelUuid).build();
+ mDevicePresenceProcessor.stopObservingDevicePresence(
+ request, packageName, userId, /* enforcePermissions */ false);
+ }
+ break;
+ }
+
case "get-backup-payload": {
final int userId = getNextIntArgRequired();
byte[] payload = mBackupRestoreProcessor.getBackupPayload(userId);
@@ -515,6 +553,14 @@
pw.println(" callback after simulate-device-event-device-locked");
pw.println(" command has been called.");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" start-observing-device-presence-uuid USER_ID PACKAGE_NAME UUID");
+ pw.println(" Start observing device presence base on the UUID.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" stop-observing-device-presence-uuid USER_ID PACKAGE_NAME UUID");
+ pw.println(" Stop observing device presence base on the UUID.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
}
pw.println(" remove-inactive-associations");
diff --git a/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java b/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
index af49df6..a374d27 100644
--- a/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
+++ b/services/companion/java/com/android/server/companion/devicepresence/DevicePresenceProcessor.java
@@ -181,14 +181,16 @@
* Process device presence start request.
*/
public void startObservingDevicePresence(ObservingDevicePresenceRequest request,
- String packageName, int userId) {
+ String packageName, int userId, boolean enforcePermissions) {
Slog.i(TAG,
"Start observing request=[" + request + "] for userId=[" + userId + "], package=["
+ packageName + "]...");
final ParcelUuid requestUuid = request.getUuid();
if (requestUuid != null) {
- enforceCallerCanObserveDevicePresenceByUuid(mContext);
+ if (enforcePermissions) {
+ enforceCallerCanObserveDevicePresenceByUuid(mContext, packageName, userId);
+ }
// If it's already being observed, then no-op.
if (mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
@@ -236,7 +238,7 @@
* Process device presence stop request.
*/
public void stopObservingDevicePresence(ObservingDevicePresenceRequest request,
- String packageName, int userId) {
+ String packageName, int userId, boolean enforcePermissions) {
Slog.i(TAG,
"Stop observing request=[" + request + "] for userId=[" + userId + "], package=["
+ packageName + "]...");
@@ -244,7 +246,9 @@
final ParcelUuid requestUuid = request.getUuid();
if (requestUuid != null) {
- enforceCallerCanObserveDevicePresenceByUuid(mContext);
+ if (enforcePermissions) {
+ enforceCallerCanObserveDevicePresenceByUuid(mContext, packageName, userId);
+ }
if (!mObservableUuidStore.isUuidBeingObserved(requestUuid, userId, packageName)) {
Slog.i(TAG, "UUID=[" + requestUuid + "], package=[" + packageName + "], userId=["
@@ -283,7 +287,7 @@
* For legacy device presence below Android V.
*
* @deprecated Use {@link #startObservingDevicePresence(ObservingDevicePresenceRequest, String,
- * int)}
+ * int, boolean)}
*/
@Deprecated
public void startObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -306,14 +310,14 @@
startObservingDevicePresence(
new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
- .build(), packageName, userId);
+ .build(), packageName, userId, /* enforcePermissions */ true);
}
/**
* For legacy device presence below Android V.
*
* @deprecated Use {@link #stopObservingDevicePresence(ObservingDevicePresenceRequest, String,
- * int)}
+ * int, boolean)}
*/
@Deprecated
public void stopObservingDevicePresence(int userId, String packageName, String deviceAddress)
@@ -336,7 +340,7 @@
stopObservingDevicePresence(
new ObservingDevicePresenceRequest.Builder().setAssociationId(association.getId())
- .build(), packageName, userId);
+ .build(), packageName, userId, /* enforcePermissions */ true);
}
/**
diff --git a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
index 796d285..c927cd0 100644
--- a/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
+++ b/services/companion/java/com/android/server/companion/utils/PermissionsUtils.java
@@ -35,6 +35,8 @@
import static android.os.Process.SYSTEM_UID;
import static android.os.UserHandle.getCallingUserId;
+import static com.android.server.companion.utils.RolesUtils.isRoleHolder;
+
import static java.util.Collections.unmodifiableMap;
import android.Manifest;
@@ -44,6 +46,7 @@
import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
import android.content.Context;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
@@ -203,11 +206,9 @@
/**
* Require the caller to hold necessary permission to observe device presence by UUID.
*/
- public static void enforceCallerCanObserveDevicePresenceByUuid(@NonNull Context context) {
- if (context.checkCallingPermission(REQUEST_OBSERVE_DEVICE_UUID_PRESENCE)
- != PERMISSION_GRANTED
- || context.checkCallingPermission(BLUETOOTH_SCAN) != PERMISSION_GRANTED
- || context.checkCallingPermission(BLUETOOTH_CONNECT) != PERMISSION_GRANTED) {
+ public static void enforceCallerCanObserveDevicePresenceByUuid(@NonNull Context context,
+ String packageName, int userId) {
+ if (!hasRequirePermissions(context, packageName, userId)) {
throw new SecurityException("Caller (uid=" + getCallingUid() + ") does not have "
+ "permissions to request observing device presence base on the UUID");
}
@@ -234,6 +235,17 @@
return sAppOpsService;
}
+ private static boolean hasRequirePermissions(
+ @NonNull Context context, String packageName, int userId) {
+ return context.checkCallingPermission(
+ REQUEST_OBSERVE_DEVICE_UUID_PRESENCE) == PERMISSION_GRANTED
+ && context.checkCallingPermission(BLUETOOTH_SCAN) == PERMISSION_GRANTED
+ && context.checkCallingPermission(BLUETOOTH_CONNECT) == PERMISSION_GRANTED
+ && Boolean.TRUE.equals(Binder.withCleanCallingIdentity(
+ () -> isRoleHolder(context, userId, packageName,
+ DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)));
+ }
+
// DO NOT USE DIRECTLY! Access via getAppOpsService().
private static IAppOpsService sAppOpsService = null;
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 2607ed3..89c888c 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.service.contentcapture.ContentCaptureService.ASSIST_CONTENT_ACTIVITY_START_KEY;
import static android.service.contentcapture.ContentCaptureService.setClientState;
import static android.view.contentcapture.ContentCaptureHelper.toList;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS;
@@ -28,6 +29,7 @@
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -44,6 +46,7 @@
import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_WRITE_FINISHED;
import static com.android.internal.util.FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__REJECT_DATA_SHARE_REQUEST;
import static com.android.internal.util.SyncResultReceiver.bundleFor;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,10 +55,12 @@
import android.app.ActivityThread;
import android.app.admin.DevicePolicyCache;
import android.app.assist.ActivityId;
+import android.app.assist.AssistContent;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ActivityPresentationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -184,6 +189,9 @@
@Nullable
private boolean mDisabledByDeviceConfig;
+ @GuardedBy("mLock")
+ private boolean activityStartAssistDataEnabled;
+
// Device-config settings that are cached and passed back to apps
@GuardedBy("mLock")
int mDevCfgLoggingLevel;
@@ -451,6 +459,8 @@
case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT:
setFineTuneParamsFromDeviceConfig();
return;
+ case DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT:
+ setActivityStartAssistDataEnabled();
default:
Slog.i(TAG, "Ignoring change on " + key);
}
@@ -639,6 +649,15 @@
final String enabled = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
setDisabledByDeviceConfig(enabled);
+ setActivityStartAssistDataEnabled();
+ }
+
+ private void setActivityStartAssistDataEnabled() {
+ synchronized (mLock) {
+ this.activityStartAssistDataEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+ DEVICE_CONFIG_ENABLE_ACTIVITY_START_ASSIST_CONTENT, false);
+ }
}
private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) {
@@ -908,6 +927,9 @@
pw.print(prefix2);
pw.print("contentProtectionAutoDisconnectTimeoutMs: ");
pw.println(mDevCfgContentProtectionAutoDisconnectTimeoutMs);
+ pw.print(prefix2);
+ pw.print("activityStartAssistDataEnabled: ");
+ pw.println(activityStartAssistDataEnabled);
pw.print(prefix);
pw.println("Global Options:");
mGlobalContentCaptureOptions.dump(prefix2, pw);
@@ -1327,6 +1349,33 @@
}
@Override
+ @SuppressWarnings("GuardedBy")
+ public boolean sendActivityStartAssistData(@UserIdInt int userId,
+ @NonNull IBinder activityToken,
+ @NonNull Intent intentData) {
+ synchronized (mLock) {
+ if (!activityStartAssistDataEnabled) {
+ return false;
+ }
+ Intent intent = new Intent(intentData);
+ intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
+ Bundle assistContentExtras = new Bundle();
+ assistContentExtras.putBoolean(ASSIST_CONTENT_ACTIVITY_START_KEY, true);
+ AssistContent assistContent = new AssistContent(assistContentExtras);
+ assistContent.setDefaultIntent(intent);
+
+ final Bundle activityAssistData = new Bundle();
+ activityAssistData.putParcelable(ASSIST_KEY_CONTENT, assistContent);
+ final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ return service.sendActivityAssistDataLocked(activityToken, activityAssistData);
+ }
+ }
+ return false;
+ }
+
+ @Override
public boolean sendActivityAssistData(@UserIdInt int userId, @NonNull IBinder activityToken,
@NonNull Bundle data) {
synchronized (mLock) {
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
index bc35fea..38bbfc4 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java
@@ -47,6 +47,7 @@
import android.app.contextualsearch.ContextualSearchState;
import android.app.contextualsearch.IContextualSearchCallback;
import android.app.contextualsearch.IContextualSearchManager;
+import android.app.contextualsearch.flags.Flags;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -91,6 +92,8 @@
private static final String TAG = ContextualSearchManagerService.class.getSimpleName();
private static final int MSG_RESET_TEMPORARY_PACKAGE = 0;
private static final int MAX_TEMP_PACKAGE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
+ private static final int MSG_INVALIDATE_TOKEN = 1;
+ private static final int MAX_TOKEN_VALID_DURATION_MS = 1_000 * 60 * 10; // 10 minutes
private final Context mContext;
private final ActivityTaskManagerInternal mAtmInternal;
@@ -145,6 +148,8 @@
private Handler mTemporaryHandler;
@GuardedBy("this")
private String mTemporaryPackage = null;
+ @GuardedBy("this")
+ private long mTokenValidDurationMs = MAX_TOKEN_VALID_DURATION_MS;
@GuardedBy("mLock")
private IContextualSearchCallback mStateCallback;
@@ -212,6 +217,29 @@
}
}
+ void resetTokenValidDurationMs() {
+ setTokenValidDurationMs(MAX_TOKEN_VALID_DURATION_MS);
+ }
+
+ void setTokenValidDurationMs(int durationMs) {
+ synchronized (this) {
+ enforceOverridingPermission("setTokenValidDurationMs");
+ if (durationMs > MAX_TOKEN_VALID_DURATION_MS) {
+ throw new IllegalArgumentException(
+ "Token max duration is " + MAX_TOKEN_VALID_DURATION_MS + " (called with "
+ + durationMs + ")");
+ }
+ mTokenValidDurationMs = durationMs;
+ if (DEBUG_USER) Log.d(TAG, "mTokenValidDurationMs set to " + durationMs);
+ }
+ }
+
+ private long getTokenValidDurationMs() {
+ synchronized (this) {
+ return mTokenValidDurationMs;
+ }
+ }
+
private Intent getResolvedLaunchIntent() {
synchronized (this) {
// If mTemporaryPackage is not null, use it to get the ContextualSearch intent.
@@ -356,15 +384,51 @@
}
private class ContextualSearchManagerStub extends IContextualSearchManager.Stub {
+ @GuardedBy("this")
+ private Handler mTokenHandler;
private @Nullable CallbackToken mToken;
+ private void invalidateToken() {
+ synchronized (this) {
+ if (mTokenHandler != null) {
+ mTokenHandler.removeMessages(MSG_INVALIDATE_TOKEN);
+ mTokenHandler = null;
+ }
+ if (DEBUG_USER) Log.d(TAG, "mToken invalidated.");
+ mToken = null;
+ }
+ }
+
+ private void issueToken() {
+ synchronized (this) {
+ mToken = new CallbackToken();
+ if (mTokenHandler == null) {
+ mTokenHandler = new Handler(Looper.getMainLooper(), null, true) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_INVALIDATE_TOKEN) {
+ invalidateToken();
+ } else {
+ Slog.wtf(TAG, "invalid token handler msg: " + msg);
+ }
+ }
+ };
+ } else {
+ mTokenHandler.removeMessages(MSG_INVALIDATE_TOKEN);
+ }
+ mTokenHandler.sendEmptyMessageDelayed(
+ MSG_INVALIDATE_TOKEN, getTokenValidDurationMs());
+ }
+ }
+
@Override
public void startContextualSearch(int entrypoint) {
synchronized (this) {
if (DEBUG_USER) Log.d(TAG, "startContextualSearch");
enforcePermission("startContextualSearch");
mAssistDataRequester.cancel();
- mToken = new CallbackToken();
+ // Creates a new CallbackToken at mToken and an expiration handler.
+ issueToken();
// We get the launch intent with the system server's identity because the system
// server has READ_FRAME_BUFFER permission to get the screenshot and because only
// the system server can invoke non-exported activities.
@@ -397,7 +461,18 @@
}
return;
}
- mToken = null;
+ invalidateToken();
+ if (Flags.enableTokenRefresh()) {
+ issueToken();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(ContextualSearchManager.EXTRA_TOKEN, mToken);
+ try {
+ callback.onResult(
+ new ContextualSearchState(null, null, bundle));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error invoking ContextualSearchCallback", e);
+ }
+ }
synchronized (mLock) {
mStateCallback = callback;
}
diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java
index 5777e1d..66a4e7b 100644
--- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java
+++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerShellCommand.java
@@ -52,6 +52,19 @@
+ packageName + " for " + duration + "ms");
break;
}
+ case "token-duration": {
+ String durationStr = getNextArg();
+ if (durationStr == null) {
+ mService.resetTokenValidDurationMs();
+ pw.println("ContextualSearchManagerService token duration reset.");
+ return 0;
+ }
+ final int durationMs = Integer.parseInt(durationStr);
+ mService.setTokenValidDurationMs(durationMs);
+ pw.println("ContextualSearchManagerService temporarily set token duration"
+ + " to " + durationMs + "ms");
+ break;
+ }
}
}
break;
@@ -72,6 +85,9 @@
pw.println(" Temporarily (for DURATION ms) changes the Contextual Search "
+ "implementation.");
pw.println(" To reset, call without any arguments.");
+ pw.println(" set token-duration [DURATION]");
+ pw.println(" Changes the Contextual Search token duration to DURATION ms.");
+ pw.println(" To reset, call without any arguments.");
pw.println("");
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 26aa053..f5a297b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -169,6 +169,17 @@
*/
static final String KEY_ENABLE_NEW_OOMADJ = "enable_new_oom_adj";
+ /**
+ * Whether or not to enable the batching of OOM adjuster calls to LMKD
+ */
+ static final String KEY_ENABLE_BATCHING_OOM_ADJ = "enable_batching_oom_adj";
+
+ /**
+ * How long to wait before scheduling another follow-up oomAdjuster update for time based state.
+ */
+ static final String KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION =
+ "follow_up_oomadj_update_wait_duration";
+
private static final int DEFAULT_MAX_CACHED_PROCESSES = 1024;
private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -231,7 +242,7 @@
static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60 * 1000;
static final long DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME_MS = 60 * 1000;
- static final boolean DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE = true;
+ static final boolean DEFAULT_KILL_BG_RESTRICTED_CACHED_IDLE = false;
static final int DEFAULT_MAX_SERVICE_CONNECTIONS_PER_PROCESS = 3000;
@@ -244,6 +255,16 @@
private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = Flags.oomadjusterCorrectnessRewrite();
/**
+ * The default value to {@link #KEY_ENABLE_BATCHING_OOM_ADJ}.
+ */
+ private static final boolean DEFAULT_ENABLE_BATCHING_OOM_ADJ = Flags.batchingOomAdj();
+
+ /**
+ * The default value to {@link #KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION}.
+ */
+ private static final long DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION = 1000L;
+
+ /**
* Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED}
*/
private static final int
@@ -1136,6 +1157,13 @@
/** @see #KEY_ENABLE_NEW_OOMADJ */
public boolean ENABLE_NEW_OOMADJ = DEFAULT_ENABLE_NEW_OOM_ADJ;
+ /** @see #KEY_ENABLE_BATCHING_OOM_ADJ */
+ public boolean ENABLE_BATCHING_OOM_ADJ = DEFAULT_ENABLE_BATCHING_OOM_ADJ;
+
+ /** @see #KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION */
+ public long FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION =
+ DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION;
+
/**
* Indicates whether PSS profiling in AppProfiler is disabled or not.
*/
@@ -1346,6 +1374,9 @@
case KEY_PROC_STATE_DEBUG_UIDS:
updateProcStateDebugUids();
break;
+ case KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION:
+ updateFollowUpOomAdjUpdateWaitDuration();
+ break;
default:
updateFGSPermissionEnforcementFlagsIfNecessary(name);
break;
@@ -1479,6 +1510,8 @@
private void loadNativeBootDeviceConfigConstants() {
ENABLE_NEW_OOMADJ = getDeviceConfigBoolean(KEY_ENABLE_NEW_OOMADJ,
DEFAULT_ENABLE_NEW_OOM_ADJ);
+ ENABLE_BATCHING_OOM_ADJ = getDeviceConfigBoolean(KEY_ENABLE_BATCHING_OOM_ADJ,
+ DEFAULT_ENABLE_BATCHING_OOM_ADJ);
}
public void setOverrideMaxCachedProcesses(int value) {
@@ -2231,6 +2264,13 @@
DEFAULT_ENABLE_NEW_OOM_ADJ);
}
+ private void updateFollowUpOomAdjUpdateWaitDuration() {
+ FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION,
+ DEFAULT_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
+ }
+
private void updateFGSPermissionEnforcementFlagsIfNecessary(@NonNull String name) {
ForegroundServiceTypePolicy.getDefaultPolicy()
.updatePermissionEnforcementFlagIfNecessary(name);
@@ -2248,6 +2288,13 @@
mDefaultPssToRssThresholdModifier);
}
+ private void updateEnableBatchingOomAdj() {
+ ENABLE_BATCHING_OOM_ADJ = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ KEY_ENABLE_BATCHING_OOM_ADJ,
+ DEFAULT_ENABLE_BATCHING_OOM_ADJ);
+ }
+
boolean shouldDebugUidForProcState(int uid) {
SparseBooleanArray ar = mProcStateDebugUids;
final var size = ar.size();
@@ -2476,6 +2523,9 @@
pw.print(" "); pw.print(KEY_MAX_PREVIOUS_TIME);
pw.print("="); pw.println(MAX_PREVIOUS_TIME);
+ pw.print(" "); pw.print(KEY_ENABLE_BATCHING_OOM_ADJ);
+ pw.print("="); pw.println(ENABLE_BATCHING_OOM_ADJ);
+
pw.println();
if (mOverrideMaxCachedProcesses >= 0) {
pw.print(" mOverrideMaxCachedProcesses="); pw.println(mOverrideMaxCachedProcesses);
@@ -2489,6 +2539,9 @@
pw.print(" ENABLE_WAIT_FOR_FINISH_ATTACH_APPLICATION=");
pw.println(mEnableWaitForFinishAttachApplication);
+ pw.print(" "); pw.print(KEY_FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
+ pw.print("="); pw.println(FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION);
+
synchronized (mProcStateDebugUids) {
pw.print(" "); pw.print(KEY_PROC_STATE_DEBUG_UIDS);
pw.print("="); pw.println(mProcStateDebugUids);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 44e522f..8dad9ac 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1663,6 +1663,7 @@
static final int BIND_APPLICATION_TIMEOUT_HARD_MSG = 83;
static final int SERVICE_FGS_TIMEOUT_MSG = 84;
static final int SERVICE_FGS_CRASH_TIMEOUT_MSG = 85;
+ static final int FOLLOW_UP_OOMADJUSTER_UPDATE_MSG = 86;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2036,6 +2037,9 @@
case SERVICE_FGS_CRASH_TIMEOUT_MSG: {
mServices.onFgsCrashTimeout((ServiceRecord) msg.obj);
} break;
+ case FOLLOW_UP_OOMADJUSTER_UPDATE_MSG: {
+ handleFollowUpOomAdjusterUpdate();
+ } break;
}
}
}
@@ -5103,6 +5107,15 @@
mAnrHelper.appNotResponding(app, TimeoutRecord.forAppStart(anrMessage));
}
+ private void handleFollowUpOomAdjusterUpdate() {
+ // Remove any existing duplicate messages on the handler here while no lock is being held.
+ // If another follow up update is needed, it will be scheduled by OomAdjuster.
+ mHandler.removeMessages(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG);
+ synchronized (this) {
+ mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ }
+ }
+
/**
* @return The last part of the string of an intent's action.
*/
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index ab34dd4..e8af82e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -49,6 +49,7 @@
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_COMPONENT_DISABLED;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_EXECUTING_SERVICE;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FINISH_RECEIVER;
+import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_FOLLOW_UP;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_GET_PROVIDER;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_PROCESS_BEGIN;
@@ -91,6 +92,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
+import static com.android.server.am.ActivityManagerService.FOLLOW_UP_OOMADJUSTER_UPDATE_MSG;
import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
import static com.android.server.am.ActivityManagerService.TAG_LRU;
@@ -226,6 +228,8 @@
return AppProtoEnums.OOM_ADJ_REASON_RESTRICTION_CHANGE;
case OOM_ADJ_REASON_COMPONENT_DISABLED:
return AppProtoEnums.OOM_ADJ_REASON_COMPONENT_DISABLED;
+ case OOM_ADJ_REASON_FOLLOW_UP:
+ return AppProtoEnums.OOM_ADJ_REASON_FOLLOW_UP;
default:
return AppProtoEnums.OOM_ADJ_REASON_UNKNOWN_TO_PROTO;
}
@@ -280,6 +284,8 @@
return OOM_ADJ_REASON_METHOD + "_restrictionChange";
case OOM_ADJ_REASON_COMPONENT_DISABLED:
return OOM_ADJ_REASON_METHOD + "_componentDisabled";
+ case OOM_ADJ_REASON_FOLLOW_UP:
+ return OOM_ADJ_REASON_METHOD + "_followUp";
default:
return "_unknown";
}
@@ -370,6 +376,7 @@
protected final int[] mTmpSchedGroup = new int[1];
final ActivityManagerService mService;
+ final Injector mInjector;
final ProcessList mProcessList;
final ActivityManagerGlobalLock mProcLock;
@@ -384,6 +391,13 @@
protected final ArraySet<ProcessRecord> mProcessesInCycle = new ArraySet<>();
/**
+ * List of processes that we want to batch for LMKD to adjust their respective
+ * OOM scores.
+ */
+ @GuardedBy("mService")
+ protected final ArrayList<ProcessRecord> mProcsToOomAdj = new ArrayList<ProcessRecord>();
+
+ /**
* Flag to mark if there is an ongoing oomAdjUpdate: potentially the oomAdjUpdate
* could be called recursively because of the indirect calls during the update;
* however the oomAdjUpdate itself doesn't support recursion - in this case we'd
@@ -413,12 +427,33 @@
@GuardedBy("mService")
protected int mProcessStateCurTop = PROCESS_STATE_TOP;
- /** Overrideable by a test */
+ @GuardedBy("mService")
+ private final ArraySet<ProcessRecord> mFollowUpUpdateSet = new ArraySet<>();
+
+ private static final long NO_FOLLOW_UP_TIME = Long.MAX_VALUE;
+ @GuardedBy("mService")
+ private long mNextFollowUpUpdateUptimeMs = NO_FOLLOW_UP_TIME;
+
@VisibleForTesting
- protected boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
+ public static class Injector {
+ boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
+ ApplicationInfo app, boolean defaultValue) {
+ return PlatformCompatCache.getInstance()
+ .isChangeEnabled(cachedCompatChangeId, app, defaultValue);
+ }
+
+ long getUptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+
+ long getElapsedRealtimeMillis() {
+ return SystemClock.elapsedRealtime();
+ }
+ }
+
+ boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId,
ApplicationInfo app, boolean defaultValue) {
- return PlatformCompatCache.getInstance()
- .isChangeEnabled(cachedCompatChangeId, app, defaultValue);
+ return mInjector.isChangeEnabled(cachedCompatChangeId, app, defaultValue);
}
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
@@ -436,7 +471,18 @@
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
ServiceThread adjusterThread) {
+ this(service, processList, activeUids, adjusterThread, new Injector());
+ }
+
+ OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
+ Injector injector) {
+ this(service, processList, activeUids, createAdjusterThread(), injector);
+ }
+
+ OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
+ ServiceThread adjusterThread, Injector injector) {
mService = service;
+ mInjector = injector;
mProcessList = processList;
mProcLock = service.mProcLock;
mActiveUids = activeUids;
@@ -624,8 +670,8 @@
// processes, its adj could be still unknown as of now, assign one.
processes.add(app);
assignCachedAdjIfNecessary(processes);
- applyOomAdjLSP(app, false, SystemClock.uptimeMillis(),
- SystemClock.elapsedRealtime(), oomAdjReason);
+ applyOomAdjLSP(app, false, mInjector.getUptimeMillis(),
+ mInjector.getElapsedRealtimeMillis(), oomAdjReason);
}
mTmpProcessList.clear();
mService.clearPendingTopAppLocked();
@@ -842,6 +888,40 @@
}
@GuardedBy("mService")
+ void updateOomAdjFollowUpTargetsLocked() {
+ final long now = mInjector.getUptimeMillis();
+ long nextFollowUpUptimeMs = Long.MAX_VALUE;
+ mNextFollowUpUpdateUptimeMs = NO_FOLLOW_UP_TIME;
+ for (int i = mFollowUpUpdateSet.size() - 1; i >= 0; i--) {
+ final ProcessRecord proc = mFollowUpUpdateSet.valueAtUnchecked(i);
+ final long followUpUptimeMs = proc.mState.getFollowupUpdateUptimeMs();
+
+ if (proc.isKilled()) {
+ // Process is dead, just remove from follow up set.
+ mFollowUpUpdateSet.removeAt(i);
+ } else if (followUpUptimeMs <= now) {
+ // Add processes that need a follow up update.
+ mPendingProcessSet.add(proc);
+ proc.mState.setFollowupUpdateUptimeMs(NO_FOLLOW_UP_TIME);
+ mFollowUpUpdateSet.removeAt(i);
+ } else if (followUpUptimeMs < nextFollowUpUptimeMs) {
+ // Figure out when to schedule the next follow up update.
+ nextFollowUpUptimeMs = followUpUptimeMs;
+ } else if (followUpUptimeMs == NO_FOLLOW_UP_TIME) {
+ // The follow up is no longer needed for this process.
+ mFollowUpUpdateSet.removeAt(i);
+ }
+ }
+
+ if (nextFollowUpUptimeMs != Long.MAX_VALUE) {
+ // There is still at least one process that needs a follow up.
+ scheduleFollowUpOomAdjusterUpdateLocked(nextFollowUpUptimeMs, now);
+ }
+
+ updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_FOLLOW_UP);
+ }
+
+ @GuardedBy("mService")
protected void performUpdateOomAdjPendingTargetsLocked(@OomAdjReason int oomAdjReason) {
final ProcessRecord topApp = mService.getTopApp();
@@ -892,8 +972,8 @@
if (startProfiling) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReasonToString(oomAdjReason));
}
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long now = mInjector.getUptimeMillis();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
final int numProc = activeProcesses.size();
@@ -1019,7 +1099,7 @@
updateUidsLSP(activeUids, nowElapsed);
synchronized (mService.mProcessStats.mLock) {
- final long nowUptime = SystemClock.uptimeMillis();
+ final long nowUptime = mInjector.getUptimeMillis();
if (mService.mProcessStats.shouldWriteNowLocked(nowUptime)) {
mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
mService.mProcessStats));
@@ -1030,7 +1110,7 @@
}
if (DEBUG_OOM_ADJ) {
- final long duration = SystemClock.uptimeMillis() - now;
+ final long duration = mInjector.getUptimeMillis() - now;
if (false) {
Slog.d(TAG_OOM_ADJ, "Did OOM ADJ in " + duration + "ms",
new RuntimeException("here").fillInStackTrace());
@@ -1044,7 +1124,7 @@
protected void assignCachedAdjIfNecessary(ArrayList<ProcessRecord> lruList) {
final int numLru = lruList.size();
if (mConstants.USE_TIERED_CACHED_ADJ) {
- final long now = SystemClock.uptimeMillis();
+ final long now = mInjector.getUptimeMillis();
for (int i = numLru - 1; i >= 0; i--) {
ProcessRecord app = lruList.get(i);
final ProcessStateRecord state = app.mState;
@@ -1246,7 +1326,7 @@
if (!app.isKilledByAm() && app.getThread() != null) {
// We don't need to apply the update for the process which didn't get computed
if (state.getCompletedAdjSeq() == mAdjSeq) {
- applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason);
+ applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, true);
}
if (app.isPendingFinishAttach()) {
@@ -1348,6 +1428,11 @@
}
}
+ if (!mProcsToOomAdj.isEmpty()) {
+ ProcessList.batchSetOomAdj(mProcsToOomAdj);
+ mProcsToOomAdj.clear();
+ }
+
if (proactiveKillsEnabled // Proactive kills enabled?
&& doKillExcessiveProcesses // Should kill excessive processes?
&& freeSwapPercent < lowSwapThresholdPercent // Swap below threshold?
@@ -1722,6 +1807,10 @@
int prevProcState = getInitialProcState(app);
int prevCapability = getInitialCapability(app);
+ // Remove any follow up update this process might have. It will be rescheduled if still
+ // needed.
+ app.mState.setFollowupUpdateUptimeMs(NO_FOLLOW_UP_TIME);
+
if (app.getThread() == null) {
state.setAdjSeq(mAdjSeq);
state.setCurrentSchedulingGroup(SCHED_GROUP_BACKGROUND);
@@ -1989,6 +2078,8 @@
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ state.getLastTopTime() + mConstants.TOP_TO_FGS_GRACE_DURATION, now);
}
// If the app was recently in the foreground and has expedited jobs running,
@@ -2009,6 +2100,9 @@
if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg for EJ: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ state.getLastTopTime() + mConstants.TOP_TO_ALMOST_PERCEPTIBLE_GRACE_DURATION,
+ now);
}
if (adj > PERCEPTIBLE_APP_ADJ
@@ -2074,7 +2168,7 @@
// app to be demoted to cached.
if (procState >= PROCESS_STATE_LAST_ACTIVITY
&& state.getSetProcState() == PROCESS_STATE_LAST_ACTIVITY
- && (state.getLastStateTime() + mConstants.MAX_PREVIOUS_TIME) < now) {
+ && (state.getLastStateTime() + mConstants.MAX_PREVIOUS_TIME) <= now) {
procState = PROCESS_STATE_LAST_ACTIVITY;
schedGroup = SCHED_GROUP_BACKGROUND;
state.setAdjType("previous-expired");
@@ -2098,6 +2192,14 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
}
}
+ final long lastStateTime;
+ if (state.getSetProcState() == PROCESS_STATE_LAST_ACTIVITY) {
+ lastStateTime = state.getLastStateTime();
+ } else {
+ lastStateTime = now;
+ }
+ maybeSetProcessFollowUpUpdateLocked(app,
+ lastStateTime + mConstants.MAX_PREVIOUS_TIME, now);
}
}
@@ -2186,6 +2288,8 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to started service: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY, now);
}
}
// If we have let the service slide into the background
@@ -2340,6 +2444,8 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise adj to recent provider: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ ppr.getLastProviderTime() + mConstants.CONTENT_PROVIDER_RETAIN_TIME, now);
}
if (procState > PROCESS_STATE_LAST_ACTIVITY) {
procState = PROCESS_STATE_LAST_ACTIVITY;
@@ -2348,6 +2454,8 @@
reportOomAdjMessageLocked(TAG_OOM_ADJ,
"Raise procstate to recent provider: " + app);
}
+ maybeSetProcessFollowUpUpdateLocked(app,
+ ppr.getLastProviderTime() + mConstants.CONTENT_PROVIDER_RETAIN_TIME, now);
}
}
@@ -3246,10 +3354,16 @@
mCachedAppOptimizer.onWakefulnessChanged(wakefulness);
}
+ @GuardedBy({"mService", "mProcLock"})
+ protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
+ long nowElapsed, @OomAdjReason int oomAdjReason) {
+ return applyOomAdjLSP(app, doingAll, now, nowElapsed, oomAdjReason, false);
+ }
+
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
@GuardedBy({"mService", "mProcLock"})
protected boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
- long nowElapsed, @OomAdjReason int oomAdjReson) {
+ long nowElapsed, @OomAdjReason int oomAdjReson, boolean isBatchingOomAdj) {
boolean success = true;
final ProcessStateRecord state = app.mState;
final UidRecord uidRec = app.getUidRecord();
@@ -3266,7 +3380,12 @@
final int oldOomAdj = state.getSetAdj();
if (state.getCurAdj() != state.getSetAdj()) {
- ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
+ if (isBatchingOomAdj && mConstants.ENABLE_BATCHING_OOM_ADJ) {
+ mProcsToOomAdj.add(app);
+ } else {
+ ProcessList.setOomAdj(app.getPid(), app.uid, state.getCurAdj());
+ }
+
if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {
String msg = "Set " + app.getPid() + " " + app.processName + " adj "
+ state.getCurAdj() + ": " + state.getAdjType();
@@ -3649,7 +3768,7 @@
if (N <= 0) {
return;
}
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
long nextTime = 0;
if (mService.mLocalPowerManager != null) {
@@ -3884,7 +4003,7 @@
}
// Take a dry run of the computeServiceHostOomAdjLSP, this would't be expensive
// since it's only evaluating one service connection.
- return computeServiceHostOomAdjLSP(cr, app, client, SystemClock.uptimeMillis(),
+ return computeServiceHostOomAdjLSP(cr, app, client, mInjector.getUptimeMillis(),
mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE,
CACHED_APP_MIN_ADJ, false, true /* dryRun */);
}
@@ -3919,7 +4038,7 @@
// The provider host process has better states than the client, so no change.
return false;
}
- return computeProviderHostOomAdjLSP(null, app, client, SystemClock.uptimeMillis(),
+ return computeProviderHostOomAdjLSP(null, app, client, mInjector.getUptimeMillis(),
mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE, CACHED_APP_MIN_ADJ,
false, true /* dryRun */);
}
@@ -3947,4 +4066,43 @@
}
return false;
}
+
+ @GuardedBy("mService")
+ private void maybeSetProcessFollowUpUpdateLocked(ProcessRecord proc,
+ long updateUptimeMs, long now) {
+ if (!Flags.followUpOomadjUpdates()) {
+ return;
+ }
+ if (updateUptimeMs <= now) {
+ // Time sensitive period has already passed. No need to schedule a follow up.
+ return;
+ }
+
+ mFollowUpUpdateSet.add(proc);
+ proc.mState.setFollowupUpdateUptimeMs(updateUptimeMs);
+
+ scheduleFollowUpOomAdjusterUpdateLocked(updateUptimeMs, now);
+ }
+
+
+ @GuardedBy("mService")
+ private void scheduleFollowUpOomAdjusterUpdateLocked(long updateUptimeMs,
+ long now) {
+ if (updateUptimeMs + mConstants.FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION
+ >= mNextFollowUpUpdateUptimeMs) {
+ // Update time is too close or later than the next follow up update.
+ return;
+ }
+ if (updateUptimeMs < now + mConstants.FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION) {
+ // Use a minimum delay for the follow up to possibly batch multiple process
+ // evaluations and avoid rapid updates.
+ updateUptimeMs = now + mConstants.FOLLOW_UP_OOMADJ_UPDATE_WAIT_DURATION;
+ }
+
+ // Schedulate a follow up update. Don't bother deleting existing handler messages, they
+ // will be cleared during the message while no locks are being held.
+ mNextFollowUpUpdateUptimeMs = updateUptimeMs;
+ mService.mHandler.sendEmptyMessageAtTime(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG,
+ mNextFollowUpUpdateUptimeMs);
+ }
}
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index a67af89..21842db 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -68,7 +68,6 @@
import android.app.ActivityManagerInternal.OomAdjReason;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
-import android.os.SystemClock;
import android.os.Trace;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -764,6 +763,11 @@
super(service, processList, activeUids, adjusterThread);
}
+ OomAdjusterModernImpl(ActivityManagerService service, ProcessList processList,
+ ActiveUids activeUids, Injector injector) {
+ super(service, processList, activeUids, injector);
+ }
+
private final ProcessRecordNodes mProcessRecordProcStateNodes = new ProcessRecordNodes(
ProcessRecordNode.NODE_TYPE_PROC_STATE, PROC_STATE_SLOTS.length);
private final ProcessRecordNodes mProcessRecordAdjNodes = new ProcessRecordNodes(
@@ -924,8 +928,8 @@
@GuardedBy({"mService", "mProcLock"})
private void fullUpdateLSP(@OomAdjReason int oomAdjReason) {
final ProcessRecord topApp = mService.getTopApp();
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long now = mInjector.getUptimeMillis();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
mAdjSeq++;
@@ -1015,8 +1019,8 @@
@GuardedBy({"mService", "mProcLock"})
private void partialUpdateLSP(@OomAdjReason int oomAdjReason, ArraySet<ProcessRecord> targets) {
final ProcessRecord topApp = mService.getTopApp();
- final long now = SystemClock.uptimeMillis();
- final long nowElapsed = SystemClock.elapsedRealtime();
+ final long now = mInjector.getUptimeMillis();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long oldTime = now - mConstants.mMaxEmptyTimeMillis;
ActiveUids activeUids = mTmpUidRecords;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 219de70..c094724 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -354,6 +354,7 @@
// LMK_KILL_OCCURRED
// LMK_START_MONITORING
// LMK_BOOT_COMPLETED
+ // LMK_PROCS_PRIO
static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2;
@@ -365,6 +366,7 @@
static final byte LMK_KILL_OCCURRED = 8; // Msg to subscribed clients on kill occurred event
static final byte LMK_START_MONITORING = 9; // Start monitoring if delayed earlier
static final byte LMK_BOOT_COMPLETED = 10;
+ static final byte LMK_PROCS_PRIO = 11; // Batch option for LMK_PROCPRIO
// Low Memory Killer Daemon command codes.
// These must be kept in sync with async_event_type definitions in lmkd.h
@@ -1561,6 +1563,50 @@
}
}
+
+ // The max size for PROCS_PRIO cmd in LMKD
+ private static final int MAX_PROCS_PRIO_PACKET_SIZE = 3;
+
+ // (4 bytes per field * 4 fields * 3 processes per batch) + 4 bytes for the LMKD cmd
+ private static final int MAX_OOM_ADJ_BATCH_LENGTH = ((4 * 4) * MAX_PROCS_PRIO_PACKET_SIZE) + 4;
+
+ /**
+ * Set the out-of-memory badness adjustment for a list of processes.
+ *
+ * @param apps App list to adjust their respective oom score.
+ *
+ * {@hide}
+ */
+ public static void batchSetOomAdj(ArrayList<ProcessRecord> apps) {
+ final int totalApps = apps.size();
+ if (totalApps == 0) {
+ return;
+ }
+
+ ByteBuffer buf = ByteBuffer.allocate(MAX_OOM_ADJ_BATCH_LENGTH);
+ int total_procs_in_buf = 0;
+ buf.putInt(LMK_PROCS_PRIO);
+ for (int i = 0; i < totalApps; i++) {
+ final int pid = apps.get(i).getPid();
+ final int amt = apps.get(i).mState.getCurAdj();
+ final int uid = apps.get(i).uid;
+ if (pid <= 0 || amt == UNKNOWN_ADJ) continue;
+ if (total_procs_in_buf >= MAX_PROCS_PRIO_PACKET_SIZE) {
+ writeLmkd(buf, null);
+ buf.clear();
+ total_procs_in_buf = 0;
+ buf.allocate(MAX_OOM_ADJ_BATCH_LENGTH);
+ buf.putInt(LMK_PROCS_PRIO);
+ }
+ buf.putInt(pid);
+ buf.putInt(uid);
+ buf.putInt(amt);
+ buf.putInt(0); // Default proc type to PROC_TYPE_APP
+ total_procs_in_buf++;
+ }
+ writeLmkd(buf, null);
+ }
+
/*
* {@hide}
*/
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 8de748e..7c64298 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -449,6 +449,9 @@
@GuardedBy("mService")
private boolean mScheduleLikeTopApp = false;
+ @GuardedBy("mService")
+ private long mFollowupUpdateUptimeMs = Long.MAX_VALUE;
+
ProcessStateRecord(ProcessRecord app) {
mApp = app;
mService = app.mService;
@@ -1164,6 +1167,16 @@
mScheduleLikeTopApp = scheduleLikeTopApp;
}
+ @GuardedBy("mService")
+ long getFollowupUpdateUptimeMs() {
+ return mFollowupUpdateUptimeMs;
+ }
+
+ @GuardedBy("mService")
+ void setFollowupUpdateUptimeMs(long updateUptimeMs) {
+ mFollowupUpdateUptimeMs = updateUptimeMs;
+ }
+
@GuardedBy(anyOf = {"mService", "mProcLock"})
public String makeAdjReason() {
if (mAdjSource != null || mAdjTarget != null) {
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index afde4f7..bb52857 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -134,3 +134,21 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "batching_oom_adj"
+ namespace: "backstage_power"
+ description: "Batch OOM adjustment calls to LMKD"
+ bug: "244232958"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "follow_up_oomadj_updates"
+ namespace: "backstage_power"
+ description: "Schedule follow up OomAdjuster updates for time sensitive states."
+ bug: "333450932"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
index 5b77c52..077e8ee 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java
@@ -446,6 +446,7 @@
sel.secondaryIds[i]);
if (id == null) {
Slogf.e(TAG, "invalid secondary id: %s", sel.secondaryIds[i]);
+ continue;
}
secondaryIdList.add(id);
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 34bfa6c..02a9f09 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -304,10 +304,7 @@
private static boolean isEmpty(
@NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) {
- if (sel.primaryId.type != 0) return false;
- if (sel.primaryId.value != 0) return false;
- if (!sel.secondaryIds.isEmpty()) return false;
- return true;
+ return sel.primaryId.type == 0 && sel.primaryId.value == 0 && sel.secondaryIds.isEmpty();
}
static @Nullable ProgramSelector programSelectorFromHal(
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 390ee96..17835b2 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -18,6 +18,10 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.os.Build.VERSION_CODES.M;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__OK;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_ILLEGAL_ARGUMENT;
+import static com.android.internal.util.FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_INVALID_OPERATION;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,6 +44,7 @@
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.hardware.CameraExtensionSessionStats;
+import android.hardware.CameraFeatureCombinationStats;
import android.hardware.CameraSessionStats;
import android.hardware.CameraStreamStats;
import android.hardware.ICameraService;
@@ -217,7 +222,7 @@
// Map of currently active camera IDs
private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>();
- private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>();
+ private final List<CameraEvent> mCameraEventHistory = new ArrayList<CameraEvent>();
private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
private static final IBinder nfcInterfaceToken = new Binder();
@@ -228,9 +233,16 @@
/*corePoolSize*/ 1);
/**
+ * Interface to track camera analytics
+ */
+ private interface CameraEvent {
+ void logSelf();
+ }
+
+ /**
* Structure to track camera usage
*/
- private static class CameraUsageEvent {
+ private static class CameraUsageEvent implements CameraEvent {
public final String mCameraId;
public final int mCameraFacing;
public final String mClientName;
@@ -311,6 +323,214 @@
public long getDuration() {
return mCompleted ? mDurationOrStartTimeMs : 0;
}
+
+ public void logSelf() {
+ int facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN;
+ switch(mCameraFacing) {
+ case CameraSessionStats.CAMERA_FACING_BACK:
+ facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__BACK;
+ break;
+ case CameraSessionStats.CAMERA_FACING_FRONT:
+ facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__FRONT;
+ break;
+ case CameraSessionStats.CAMERA_FACING_EXTERNAL:
+ facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL;
+ break;
+ default:
+ Slog.w(TAG, "Unknown camera facing: " + mCameraFacing);
+ }
+
+ int extensionType = FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NONE;
+ boolean extensionIsAdvanced = false;
+ int extensionCaptureFormat = ImageFormat.UNKNOWN;
+ if (mExtSessionStats != null) {
+ switch (mExtSessionStats.type) {
+ case CameraExtensionSessionStats.Type.EXTENSION_AUTOMATIC:
+ extensionType = FrameworkStatsLog
+ .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_AUTOMATIC;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_FACE_RETOUCH:
+ extensionType = FrameworkStatsLog
+ .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_FACE_RETOUCH;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_BOKEH:
+ extensionType =
+ FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_BOKEH;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_HDR:
+ extensionType =
+ FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_HDR;
+ break;
+ case CameraExtensionSessionStats.Type.EXTENSION_NIGHT:
+ extensionType =
+ FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NIGHT;
+ break;
+ default:
+ Slog.w(TAG, "Unknown extension type: " + mExtSessionStats.type);
+ }
+ extensionIsAdvanced = mExtSessionStats.isAdvanced;
+ if (Flags.analytics24q3()) {
+ extensionCaptureFormat = mExtSessionStats.captureFormat;
+ }
+ }
+
+ int streamCount = 0;
+ if (mStreamStats != null) {
+ streamCount = mStreamStats.size();
+ }
+ if (CameraServiceProxy.DEBUG) {
+ String ultrawideDebug = Flags.logUltrawideUsage()
+ ? ", wideAngleUsage " + mUsedUltraWide
+ : "";
+ String zoomOverrideDebug = Flags.logZoomOverrideUsage()
+ ? ", zoomOverrideUsage " + mUsedZoomOverride
+ : "";
+ String mostRequestedFpsRangeDebug = Flags.analytics24q3()
+ ? ", mostRequestedFpsRange " + mMostRequestedFpsRange
+ : "";
+ String extensionCaptureFormatDebug = Flags.analytics24q3()
+ ? " extensionCaptureFormat " + mExtSessionStats.captureFormat
+ : "";
+
+ Slog.v(TAG, "CAMERA_ACTION_EVENT: action " + mAction
+ + " clientName " + mClientName
+ + ", duration " + getDuration()
+ + ", APILevel " + mAPILevel
+ + ", cameraId " + mCameraId
+ + ", facing " + facing
+ + ", isNdk " + mIsNdk
+ + ", latencyMs " + mLatencyMs
+ + ", operatingMode " + mOperatingMode
+ + ", internalReconfigure " + mInternalReconfigure
+ + ", requestCount " + mRequestCount
+ + ", resultErrorCount " + mResultErrorCount
+ + ", deviceError " + mDeviceError
+ + ", streamCount is " + streamCount
+ + ", userTag is " + mUserTag
+ + ", videoStabilizationMode " + mVideoStabilizationMode
+ + ultrawideDebug
+ + zoomOverrideDebug
+ + mostRequestedFpsRangeDebug
+ + ", logId " + mLogId
+ + ", sessionIndex " + mSessionIndex
+ + ", mExtSessionStats {type " + extensionType
+ + " isAdvanced " + extensionIsAdvanced
+ + extensionCaptureFormatDebug + "}");
+ }
+
+ // Convert from CameraStreamStats to CameraStreamProto
+ CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS];
+ for (int i = 0; i < MAX_STREAM_STATISTICS; i++) {
+ streamProtos[i] = new CameraStreamProto();
+ if (i < streamCount) {
+ CameraStreamStats streamStats = mStreamStats.get(i);
+ streamProtos[i].width = streamStats.getWidth();
+ streamProtos[i].height = streamStats.getHeight();
+ streamProtos[i].format = streamStats.getFormat();
+ streamProtos[i].dataSpace = streamStats.getDataSpace();
+ streamProtos[i].usage = streamStats.getUsage();
+ streamProtos[i].requestCount = streamStats.getRequestCount();
+ streamProtos[i].errorCount = streamStats.getErrorCount();
+ streamProtos[i].firstCaptureLatencyMillis = streamStats.getStartLatencyMs();
+ streamProtos[i].maxHalBuffers = streamStats.getMaxHalBuffers();
+ streamProtos[i].maxAppBuffers = streamStats.getMaxAppBuffers();
+ streamProtos[i].histogramType = streamStats.getHistogramType();
+ streamProtos[i].histogramBins = streamStats.getHistogramBins();
+ streamProtos[i].histogramCounts = streamStats.getHistogramCounts();
+ streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile();
+ streamProtos[i].streamUseCase = streamStats.getStreamUseCase();
+ streamProtos[i].colorSpace = streamStats.getColorSpace();
+
+ if (CameraServiceProxy.DEBUG) {
+ String histogramTypeName =
+ cameraHistogramTypeToString(streamProtos[i].histogramType);
+ Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width
+ + ", height " + streamProtos[i].height
+ + ", format " + streamProtos[i].format
+ + ", maxPreviewFps " + streamStats.getMaxPreviewFps()
+ + ", dataSpace " + streamProtos[i].dataSpace
+ + ", usage " + streamProtos[i].usage
+ + ", requestCount " + streamProtos[i].requestCount
+ + ", errorCount " + streamProtos[i].errorCount
+ + ", firstCaptureLatencyMillis "
+ + streamProtos[i].firstCaptureLatencyMillis
+ + ", maxHalBuffers " + streamProtos[i].maxHalBuffers
+ + ", maxAppBuffers " + streamProtos[i].maxAppBuffers
+ + ", histogramType " + histogramTypeName
+ + ", histogramBins "
+ + Arrays.toString(streamProtos[i].histogramBins)
+ + ", histogramCounts "
+ + Arrays.toString(streamProtos[i].histogramCounts)
+ + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile
+ + ", streamUseCase " + streamProtos[i].streamUseCase
+ + ", colorSpace " + streamProtos[i].colorSpace);
+ }
+ }
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_ACTION_EVENT, getDuration(),
+ mAPILevel, mClientName, facing, mCameraId, mAction, mIsNdk,
+ mLatencyMs, mOperatingMode, mInternalReconfigure,
+ mRequestCount, mResultErrorCount, mDeviceError,
+ streamCount, MessageNano.toByteArray(streamProtos[0]),
+ MessageNano.toByteArray(streamProtos[1]),
+ MessageNano.toByteArray(streamProtos[2]),
+ MessageNano.toByteArray(streamProtos[3]),
+ MessageNano.toByteArray(streamProtos[4]),
+ mUserTag, mVideoStabilizationMode,
+ mLogId, mSessionIndex,
+ extensionType, extensionIsAdvanced, mUsedUltraWide,
+ mUsedZoomOverride,
+ mMostRequestedFpsRange.getLower(), mMostRequestedFpsRange.getUpper(),
+ extensionCaptureFormat);
+
+ }
+ }
+ /**
+ * Structure to track feature combination query
+ */
+ private static class CameraFeatureCombinationQueryEvent implements CameraEvent {
+ private CameraFeatureCombinationStats mFeatureCombinationStats;
+
+ CameraFeatureCombinationQueryEvent(CameraFeatureCombinationStats featureCombinationStats) {
+ mFeatureCombinationStats = featureCombinationStats;
+ }
+
+ public void logSelf() {
+ int statusCode = -1;
+ switch (mFeatureCombinationStats.mStatus) {
+ case 0:
+ statusCode = CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__OK;
+ break;
+ case ICameraService.ERROR_ILLEGAL_ARGUMENT:
+ statusCode = CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_ILLEGAL_ARGUMENT;
+ break;
+ case ICameraService.ERROR_INVALID_OPERATION:
+ statusCode = CAMERA_FEATURE_COMBINATION_QUERY_EVENT__STATUS_CODE__ERROR_INVALID_OPERATION;
+ break;
+ default:
+ break;
+ }
+ if (statusCode == -1) {
+ Slog.w(TAG, "Unknown feature combination query status code: "
+ + mFeatureCombinationStats.mStatus);
+ return;
+ }
+
+ if (CameraServiceProxy.DEBUG) {
+ Slog.v(TAG, "CAMERA_FEATURE_COMBINATION_QUERY_EVENT: uid "
+ + mFeatureCombinationStats.mUid
+ + ", cameraId " + mFeatureCombinationStats.mCameraId
+ + ", queryType " + mFeatureCombinationStats.mQueryType
+ + ", featureCombination " + mFeatureCombinationStats.mFeatureCombination
+ + ", status " + statusCode);
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_FEATURE_COMBINATION_QUERY_EVENT,
+ mFeatureCombinationStats.mUid,
+ mFeatureCombinationStats.mCameraId,
+ mFeatureCombinationStats.mQueryType,
+ mFeatureCombinationStats.mFeatureCombination,
+ statusCode);
+ }
}
private final class DisplayWindowListener extends IDisplayWindowListener.Stub {
@@ -625,6 +845,32 @@
}
@Override
+ public void notifyFeatureCombinationStats(CameraFeatureCombinationStats featureCombStats) {
+ if (!Flags.analytics24q3()) {
+ return;
+ }
+ if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
+ Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected "
+ + " camera service UID!");
+ return;
+ }
+
+ if (DEBUG) {
+ String combinationTypeStr = cameraFeatureCombinationTypeToString(
+ featureCombStats.mQueryType);
+ String combinationStr = cameraFeatureCombinationToString(
+ featureCombStats.mFeatureCombination);
+ Slog.v(TAG, "Camera " + featureCombStats.mCameraId
+ + " query " + combinationTypeStr
+ + " combination " + combinationStr
+ + " for client UID " + featureCombStats.mUid
+ + " returns " + featureCombStats.mStatus);
+ }
+
+ updateFeatureCombinationQuery(featureCombStats);
+ }
+
+ @Override
public boolean isCameraDisabled(int userId) {
if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
Slog.e(TAG, "Calling UID: " + Binder.getCallingUid()
@@ -684,7 +930,7 @@
switch (cmd.replace('-', '_')) {
case "dump_events":
int eventCount = mCameraServiceProxy.getUsageEventCount();
- mCameraServiceProxy.dumpUsageEvents();
+ mCameraServiceProxy.dumpCameraEvents();
pw.println("Camera usage events dumped: " + eventCount);
break;
default:
@@ -865,18 +1111,18 @@
}
private class EventWriterTask implements Runnable {
- private ArrayList<CameraUsageEvent> mEventList;
+ private List<CameraEvent> mEventList;
private static final long WRITER_SLEEP_MS = 100;
- public EventWriterTask(ArrayList<CameraUsageEvent> eventList) {
+ EventWriterTask(List<CameraEvent> eventList) {
mEventList = eventList;
}
@Override
public void run() {
if (mEventList != null) {
- for (CameraUsageEvent event : mEventList) {
- logCameraUsageEvent(event);
+ for (CameraEvent event : mEventList) {
+ event.logSelf();
try {
Thread.sleep(WRITER_SLEEP_MS);
} catch (InterruptedException e) {}
@@ -884,170 +1130,6 @@
mEventList.clear();
}
}
-
- /**
- * Write camera usage events to stats log.
- * Package-private
- */
- private void logCameraUsageEvent(CameraUsageEvent e) {
- int facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__UNKNOWN;
- switch(e.mCameraFacing) {
- case CameraSessionStats.CAMERA_FACING_BACK:
- facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__BACK;
- break;
- case CameraSessionStats.CAMERA_FACING_FRONT:
- facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__FRONT;
- break;
- case CameraSessionStats.CAMERA_FACING_EXTERNAL:
- facing = FrameworkStatsLog.CAMERA_ACTION_EVENT__FACING__EXTERNAL;
- break;
- default:
- Slog.w(TAG, "Unknown camera facing: " + e.mCameraFacing);
- }
-
- int extensionType = FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NONE;
- boolean extensionIsAdvanced = false;
- int extensionCaptureFormat = ImageFormat.UNKNOWN;
- if (e.mExtSessionStats != null) {
- switch (e.mExtSessionStats.type) {
- case CameraExtensionSessionStats.Type.EXTENSION_AUTOMATIC:
- extensionType = FrameworkStatsLog
- .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_AUTOMATIC;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_FACE_RETOUCH:
- extensionType = FrameworkStatsLog
- .CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_FACE_RETOUCH;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_BOKEH:
- extensionType =
- FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_BOKEH;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_HDR:
- extensionType =
- FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_HDR;
- break;
- case CameraExtensionSessionStats.Type.EXTENSION_NIGHT:
- extensionType =
- FrameworkStatsLog.CAMERA_ACTION_EVENT__EXT_TYPE__EXTENSION_NIGHT;
- break;
- default:
- Slog.w(TAG, "Unknown extension type: " + e.mExtSessionStats.type);
- }
- extensionIsAdvanced = e.mExtSessionStats.isAdvanced;
- if (Flags.analytics24q3()) {
- extensionCaptureFormat = e.mExtSessionStats.captureFormat;
- }
- }
-
- int streamCount = 0;
- if (e.mStreamStats != null) {
- streamCount = e.mStreamStats.size();
- }
- if (CameraServiceProxy.DEBUG) {
- String ultrawideDebug = Flags.logUltrawideUsage()
- ? ", wideAngleUsage " + e.mUsedUltraWide
- : "";
- String zoomOverrideDebug = Flags.logZoomOverrideUsage()
- ? ", zoomOverrideUsage " + e.mUsedZoomOverride
- : "";
- String mostRequestedFpsRangeDebug = Flags.analytics24q3()
- ? ", mostRequestedFpsRange " + e.mMostRequestedFpsRange
- : "";
- String extensionCaptureFormatDebug = Flags.analytics24q3()
- ? " extensionCaptureFormat " + e.mExtSessionStats.captureFormat
- : "";
-
- Slog.v(TAG, "CAMERA_ACTION_EVENT: action " + e.mAction
- + " clientName " + e.mClientName
- + ", duration " + e.getDuration()
- + ", APILevel " + e.mAPILevel
- + ", cameraId " + e.mCameraId
- + ", facing " + facing
- + ", isNdk " + e.mIsNdk
- + ", latencyMs " + e.mLatencyMs
- + ", operatingMode " + e.mOperatingMode
- + ", internalReconfigure " + e.mInternalReconfigure
- + ", requestCount " + e.mRequestCount
- + ", resultErrorCount " + e.mResultErrorCount
- + ", deviceError " + e.mDeviceError
- + ", streamCount is " + streamCount
- + ", userTag is " + e.mUserTag
- + ", videoStabilizationMode " + e.mVideoStabilizationMode
- + ultrawideDebug
- + zoomOverrideDebug
- + mostRequestedFpsRangeDebug
- + ", logId " + e.mLogId
- + ", sessionIndex " + e.mSessionIndex
- + ", mExtSessionStats {type " + extensionType
- + " isAdvanced " + extensionIsAdvanced
- + extensionCaptureFormatDebug + "}");
- }
-
- // Convert from CameraStreamStats to CameraStreamProto
- CameraStreamProto[] streamProtos = new CameraStreamProto[MAX_STREAM_STATISTICS];
- for (int i = 0; i < MAX_STREAM_STATISTICS; i++) {
- streamProtos[i] = new CameraStreamProto();
- if (i < streamCount) {
- CameraStreamStats streamStats = e.mStreamStats.get(i);
- streamProtos[i].width = streamStats.getWidth();
- streamProtos[i].height = streamStats.getHeight();
- streamProtos[i].format = streamStats.getFormat();
- streamProtos[i].dataSpace = streamStats.getDataSpace();
- streamProtos[i].usage = streamStats.getUsage();
- streamProtos[i].requestCount = streamStats.getRequestCount();
- streamProtos[i].errorCount = streamStats.getErrorCount();
- streamProtos[i].firstCaptureLatencyMillis = streamStats.getStartLatencyMs();
- streamProtos[i].maxHalBuffers = streamStats.getMaxHalBuffers();
- streamProtos[i].maxAppBuffers = streamStats.getMaxAppBuffers();
- streamProtos[i].histogramType = streamStats.getHistogramType();
- streamProtos[i].histogramBins = streamStats.getHistogramBins();
- streamProtos[i].histogramCounts = streamStats.getHistogramCounts();
- streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile();
- streamProtos[i].streamUseCase = streamStats.getStreamUseCase();
- streamProtos[i].colorSpace = streamStats.getColorSpace();
-
- if (CameraServiceProxy.DEBUG) {
- String histogramTypeName =
- cameraHistogramTypeToString(streamProtos[i].histogramType);
- Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width
- + ", height " + streamProtos[i].height
- + ", format " + streamProtos[i].format
- + ", maxPreviewFps " + streamStats.getMaxPreviewFps()
- + ", dataSpace " + streamProtos[i].dataSpace
- + ", usage " + streamProtos[i].usage
- + ", requestCount " + streamProtos[i].requestCount
- + ", errorCount " + streamProtos[i].errorCount
- + ", firstCaptureLatencyMillis "
- + streamProtos[i].firstCaptureLatencyMillis
- + ", maxHalBuffers " + streamProtos[i].maxHalBuffers
- + ", maxAppBuffers " + streamProtos[i].maxAppBuffers
- + ", histogramType " + histogramTypeName
- + ", histogramBins "
- + Arrays.toString(streamProtos[i].histogramBins)
- + ", histogramCounts "
- + Arrays.toString(streamProtos[i].histogramCounts)
- + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile
- + ", streamUseCase " + streamProtos[i].streamUseCase
- + ", colorSpace " + streamProtos[i].colorSpace);
- }
- }
- }
- FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_ACTION_EVENT, e.getDuration(),
- e.mAPILevel, e.mClientName, facing, e.mCameraId, e.mAction, e.mIsNdk,
- e.mLatencyMs, e.mOperatingMode, e.mInternalReconfigure,
- e.mRequestCount, e.mResultErrorCount, e.mDeviceError,
- streamCount, MessageNano.toByteArray(streamProtos[0]),
- MessageNano.toByteArray(streamProtos[1]),
- MessageNano.toByteArray(streamProtos[2]),
- MessageNano.toByteArray(streamProtos[3]),
- MessageNano.toByteArray(streamProtos[4]),
- e.mUserTag, e.mVideoStabilizationMode,
- e.mLogId, e.mSessionIndex,
- extensionType, extensionIsAdvanced, e.mUsedUltraWide,
- e.mUsedZoomOverride,
- e.mMostRequestedFpsRange.getLower(), e.mMostRequestedFpsRange.getUpper(),
- extensionCaptureFormat);
- }
}
/**
@@ -1055,22 +1137,22 @@
*/
int getUsageEventCount() {
synchronized (mLock) {
- return mCameraUsageHistory.size();
+ return mCameraEventHistory.size();
}
}
/**
- * Dump camera usage events to log.
+ * Dump camera events to log.
* Package-private
*/
- void dumpUsageEvents() {
+ void dumpCameraEvents() {
synchronized(mLock) {
// Randomize order of events so that it's not meaningful
- Collections.shuffle(mCameraUsageHistory);
+ Collections.shuffle(mCameraEventHistory);
mLogWriterService.execute(new EventWriterTask(
- new ArrayList<CameraUsageEvent>(mCameraUsageHistory)));
+ new ArrayList(mCameraEventHistory)));
- mCameraUsageHistory.clear();
+ mCameraEventHistory.clear();
}
final long ident = Binder.clearCallingIdentity();
try {
@@ -1288,7 +1370,7 @@
cameraId, facing, clientName, apiLevel, isNdk,
FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__OPEN,
latencyMs, sessionType, deviceError, logId, sessionIdx);
- mCameraUsageHistory.add(openEvent);
+ mCameraEventHistory.add(openEvent);
break;
case CameraSessionStats.CAMERA_STATE_ACTIVE:
// Check current active camera IDs to see if this package is already talking to
@@ -1323,7 +1405,7 @@
/*userTag*/"", /*videoStabilizationMode*/-1, /*usedUltraWide*/false,
/*usedZoomOverride*/false, new Range<Integer>(0, 0),
new CameraExtensionSessionStats());
- mCameraUsageHistory.add(oldEvent);
+ mCameraEventHistory.add(oldEvent);
}
break;
case CameraSessionStats.CAMERA_STATE_IDLE:
@@ -1335,7 +1417,7 @@
resultErrorCount, deviceError, streamStats, userTag,
videoStabilizationMode, usedUltraWide, usedZoomOverride,
mostRequestedFpsRange, extSessionStats);
- mCameraUsageHistory.add(doneEvent);
+ mCameraEventHistory.add(doneEvent);
// Do not double count device error
deviceError = false;
@@ -1362,11 +1444,11 @@
cameraId, facing, clientName, apiLevel, isNdk,
FrameworkStatsLog.CAMERA_ACTION_EVENT__ACTION__CLOSE,
latencyMs, sessionType, deviceError, logId, sessionIdx);
- mCameraUsageHistory.add(closeEvent);
+ mCameraEventHistory.add(closeEvent);
}
- if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
- dumpUsageEvents();
+ if (mCameraEventHistory.size() > MAX_USAGE_HISTORY) {
+ dumpCameraEvents();
}
break;
@@ -1378,6 +1460,18 @@
}
}
+ private void updateFeatureCombinationQuery(CameraFeatureCombinationStats featureCombStats) {
+ synchronized (mLock) {
+ CameraFeatureCombinationQueryEvent e =
+ new CameraFeatureCombinationQueryEvent(featureCombStats);
+ mCameraEventHistory.add(e);
+
+ if (mCameraEventHistory.size() > MAX_USAGE_HISTORY) {
+ dumpCameraEvents();
+ }
+ }
+ }
+
private void notifyNfcService(boolean enablePolling) {
NfcManager nfcManager = mContext.getSystemService(NfcManager.class);
if (nfcManager == null) {
@@ -1434,4 +1528,41 @@
return "HISTOGRAM_TYPE_UNKNOWN";
}
+ private static String cameraFeatureCombinationTypeToString(int featureCombinationType) {
+ switch (featureCombinationType) {
+ case CameraFeatureCombinationStats.QueryType.QUERY_FEATURE_COMBINATION:
+ return "QUERY_FEATURE_COMBINATION";
+ case CameraFeatureCombinationStats.QueryType.QUERY_SESSION_CHARACTERISTICS:
+ return "QUERY_SESSION_CHARACTERISTICS";
+ default:
+ break;
+ }
+ return "FEATURE_COMBINATION_TYPE_UNKNOWN";
+ }
+
+ private static String cameraFeatureCombinationToString(long featureCombination) {
+ StringBuilder combinationStr = new StringBuilder("{");
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_60_FPS) != 0) {
+ combinationStr.append("60fps ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_STABILIZATION)
+ != 0) {
+ combinationStr.append("stabilization ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_HLG10) != 0) {
+ combinationStr.append("hlg10 ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_JPEG) != 0) {
+ combinationStr.append("jpeg ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_JPEG_R) != 0) {
+ combinationStr.append("jpeg_r ");
+ }
+ if ((featureCombination & CameraFeatureCombinationStats.CAMERA_FEATURE_4K) != 0) {
+ combinationStr.append("4k ");
+ }
+ combinationStr.append("}");
+
+ return combinationStr.toString();
+ }
}
diff --git a/services/core/java/com/android/server/camera/CameraStatsJobService.java b/services/core/java/com/android/server/camera/CameraStatsJobService.java
index b8a6846..1227ca7 100644
--- a/services/core/java/com/android/server/camera/CameraStatsJobService.java
+++ b/services/core/java/com/android/server/camera/CameraStatsJobService.java
@@ -21,14 +21,13 @@
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.util.Slog;
-import java.util.concurrent.TimeUnit;
-
import com.android.server.LocalServices;
+import java.util.concurrent.TimeUnit;
+
/**
* A JobService to periodically collect camera usage stats.
*/
@@ -50,7 +49,7 @@
return false;
}
- serviceProxy.dumpUsageEvents();
+ serviceProxy.dumpCameraEvents();
return false;
}
diff --git a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
index 0812fd9..de7341d 100644
--- a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
+++ b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
@@ -21,6 +21,7 @@
import android.app.assist.ActivityId;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
+import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.service.contentcapture.ActivityEvent.ActivityEventType;
@@ -40,6 +41,14 @@
public abstract boolean isContentCaptureServiceForUser(int uid, @UserIdInt int userId);
/**
+ * Notifies the intelligence service of new intent data associated with an activity start event.
+ *
+ * @return {@code false} if there was no service set for the given user
+ */
+ public abstract boolean sendActivityStartAssistData(@UserIdInt int userId,
+ @NonNull IBinder activityToken, @NonNull Intent intentData);
+
+ /**
* Notifies the intelligence service of new assist data for the given activity.
*
* @return {@code false} if there was no service set for the given user
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 5fd0253..2d5f38e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -3406,6 +3406,31 @@
}
}
+ boolean requestDisplayPower(int displayId, boolean on) {
+ synchronized (mSyncRoot) {
+ final var display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ if (display == null) {
+ Slog.w(TAG, "requestDisplayPower: Cannot find a display with displayId="
+ + displayId);
+ return false;
+ }
+ final BrightnessPair brightnessPair = mDisplayBrightnesses.get(displayId);
+ var runnable = display.getPrimaryDisplayDeviceLocked().requestDisplayStateLocked(
+ on ? Display.STATE_ON : Display.STATE_OFF,
+ on ? brightnessPair.brightness : PowerManager.BRIGHTNESS_OFF_FLOAT,
+ brightnessPair.sdrBrightness,
+ display.getDisplayOffloadSessionLocked());
+ if (runnable == null) {
+ Slog.w(TAG, "requestDisplayPower: Cannot update the power state to ON=" + on
+ + " for a display with displayId=" + displayId + ", runnable is null");
+ return false;
+ }
+ runnable.run();
+ Slog.i(TAG, "requestDisplayPower(displayId=" + displayId + ", on=" + on + ")");
+ }
+ return true;
+ }
+
/**
* This is the object that everything in the display manager locks on.
* We make it an inner class within the {@link DisplayManagerService} to so that it is
@@ -4629,6 +4654,12 @@
DisplayManagerService.this.enableConnectedDisplay(displayId, false);
}
+ @EnforcePermission(MANAGE_DISPLAYS)
+ public boolean requestDisplayPower(int displayId, boolean on) {
+ requestDisplayPower_enforcePermission();
+ return DisplayManagerService.this.requestDisplayPower(displayId, on);
+ }
+
@EnforcePermission(RESTRICT_DISPLAY_MODES)
@Override // Binder call
public void requestDisplayModes(IBinder token, int displayId, @Nullable int[] modeIds) {
diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
index 8c39d7d..d973b71 100644
--- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
+++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java
@@ -106,6 +106,10 @@
return setDisplayEnabled(true);
case "disable-display":
return setDisplayEnabled(false);
+ case "power-on":
+ return requestDisplayPower(true);
+ case "power-off":
+ return requestDisplayPower(false);
default:
return handleDefaultCommands(cmd);
}
@@ -592,4 +596,21 @@
mService.enableConnectedDisplay(displayId, enable);
return 0;
}
+
+ private int requestDisplayPower(boolean enable) {
+ final String displayIdText = getNextArg();
+ if (displayIdText == null) {
+ getErrPrintWriter().println("Error: no displayId specified");
+ return 1;
+ }
+ final int displayId;
+ try {
+ displayId = Integer.parseInt(displayIdText);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: invalid displayId: '" + displayIdText + "'");
+ return 1;
+ }
+ mService.requestDisplayPower(displayId, enable);
+ return 0;
+ }
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 0bd40d1..e5dbce9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3352,6 +3352,10 @@
mPointerIconCache.setPointerFillStyle(fillStyle);
}
+ void setPointerScale(float scale) {
+ mPointerIconCache.setPointerScale(scale);
+ }
+
interface KeyboardBacklightControllerInterface {
default void incrementKeyboardBacklight(int deviceId) {}
default void decrementKeyboardBacklight(int deviceId) {}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 9585b49..593b091 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -16,6 +16,7 @@
package com.android.server.input;
+import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
import static android.view.flags.Flags.enableVectorCursorA11ySettings;
@@ -101,7 +102,9 @@
Map.entry(Settings.Secure.getUriFor(Settings.Secure.STYLUS_POINTER_ICON_ENABLED),
(reason) -> updateStylusPointerIconEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_FILL_STYLE),
- (reason) -> updatePointerFillStyleFromSettings()));
+ (reason) -> updatePointerFillStyleFromSettings()),
+ Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SCALE),
+ (reason) -> updatePointerScaleFromSettings()));
}
/**
@@ -277,4 +280,14 @@
UserHandle.USER_CURRENT);
mService.setPointerFillStyle(pointerFillStyle);
}
+
+ private void updatePointerScaleFromSettings() {
+ if (!enableVectorCursorA11ySettings()) {
+ return;
+ }
+ final float pointerScale = Settings.System.getFloatForUser(mContext.getContentResolver(),
+ Settings.System.POINTER_SCALE, DEFAULT_POINTER_SCALE,
+ UserHandle.USER_CURRENT);
+ mService.setPointerScale(pointerScale);
+ }
}
diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java
index 936e17f..44622d8 100644
--- a/services/core/java/com/android/server/input/PointerIconCache.java
+++ b/services/core/java/com/android/server/input/PointerIconCache.java
@@ -16,6 +16,7 @@
package com.android.server.input;
+import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
import android.annotation.NonNull;
@@ -63,6 +64,8 @@
@GuardedBy("mLoadedPointerIconsByDisplayAndType")
private @PointerIcon.PointerIconVectorStyleFill int mPointerIconFillStyle =
POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
+ @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+ private float mPointerIconScale = DEFAULT_POINTER_SCALE;
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
@@ -117,6 +120,11 @@
mUiThreadHandler.post(() -> handleSetPointerFillStyle(fillStyle));
}
+ /** Set the scale for vector pointer icons. */
+ public void setPointerScale(float scale) {
+ mUiThreadHandler.post(() -> handleSetPointerScale(scale));
+ }
+
/**
* Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if
* it isn't already cached.
@@ -137,7 +145,7 @@
theme.applyStyle(PointerIcon.vectorFillStyleToResource(mPointerIconFillStyle),
/* force= */ true);
icon = PointerIcon.getLoadedSystemIcon(new ContextThemeWrapper(context, theme),
- type, mUseLargePointerIcons);
+ type, mUseLargePointerIcons, mPointerIconScale);
iconsByType.put(type, icon);
}
return Objects.requireNonNull(icon);
@@ -215,6 +223,19 @@
mNative.reloadPointerIcons();
}
+ @android.annotation.UiThread
+ private void handleSetPointerScale(float scale) {
+ synchronized (mLoadedPointerIconsByDisplayAndType) {
+ if (mPointerIconScale == scale) {
+ return;
+ }
+ mPointerIconScale = scale;
+ // Clear all cached icons on all displays.
+ mLoadedPointerIconsByDisplayAndType.clear();
+ }
+ mNative.reloadPointerIcons();
+ }
+
// Updates the cached display density for the given displayId, and returns true if
// the cached density changed.
@GuardedBy("mLoadedPointerIconsByDisplayAndType")
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7f39232..6b15bce 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5241,7 +5241,8 @@
return;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final int userId = mCurrentUserId;
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
boolean reenableMinimumNonAuxSystemImes = false;
// TODO: The following code should find better place to live.
@@ -5304,18 +5305,18 @@
updateDefaultVoiceImeIfNeededLocked();
// TODO: Instantiate mSwitchingController for each user.
- if (settings.getUserId() == mSwitchingController.getUserId()) {
+ if (userId == mSwitchingController.getUserId()) {
mSwitchingController.resetCircularListLocked(settings.getMethodMap());
} else {
mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
mContext, settings.getMethodMap(), mCurrentUserId);
}
// TODO: Instantiate mHardwareKeyboardShortcutController for each user.
- if (settings.getUserId() == mHardwareKeyboardShortcutController.getUserId()) {
+ if (userId == mHardwareKeyboardShortcutController.getUserId()) {
mHardwareKeyboardShortcutController.reset(settings.getMethodMap());
} else {
mHardwareKeyboardShortcutController = new HardwareKeyboardShortcutController(
- settings.getMethodMap(), settings.getUserId());
+ settings.getMethodMap(), userId);
}
sendOnNavButtonFlagsChangedLocked();
@@ -5323,7 +5324,7 @@
// Notify InputMethodListListeners of the new installed InputMethods.
final List<InputMethodInfo> inputMethodList = settings.getMethodList();
mHandler.obtainMessage(MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED,
- settings.getUserId(), 0 /* unused */, inputMethodList).sendToTarget();
+ userId, 0 /* unused */, inputMethodList).sendToTarget();
}
@GuardedBy("ImfLock.class")
@@ -5519,44 +5520,18 @@
*/
@GuardedBy("ImfLock.class")
InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
- String selectedMethodId = getSelectedMethodIdLocked();
+ final int userId = mCurrentUserId;
+ final var selectedMethodId = getInputMethodBindingController(userId).getSelectedMethodId();
if (selectedMethodId == null) {
return null;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
- final boolean subtypeIsSelected = settings.isSubtypeSelected();
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(selectedMethodId);
if (imi == null || imi.getSubtypeCount() == 0) {
return null;
}
- if (!subtypeIsSelected || mCurrentSubtype == null
- || !SubtypeUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
- int subtypeId = settings.getSelectedInputMethodSubtypeId(selectedMethodId);
- if (subtypeId == NOT_A_SUBTYPE_ID) {
- // If there are no selected subtypes, the framework will try to find
- // the most applicable subtype from explicitly or implicitly enabled
- // subtypes.
- List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
- settings.getEnabledInputMethodSubtypeList(imi, true);
- // If there is only one explicitly or implicitly enabled subtype,
- // just returns it.
- if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
- mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
- } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
- final String locale = SystemLocaleWrapper.get(settings.getUserId())
- .get(0).toString();
- mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtype(
- explicitlyOrImplicitlyEnabledSubtypes,
- SubtypeUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
- if (mCurrentSubtype == null) {
- mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtype(
- explicitlyOrImplicitlyEnabledSubtypes, null, locale, true);
- }
- }
- } else {
- mCurrentSubtype = SubtypeUtils.getSubtypes(imi).get(subtypeId);
- }
- }
+ mCurrentSubtype = SubtypeUtils.getCurrentInputMethodSubtype(imi, settings,
+ mCurrentSubtype);
return mCurrentSubtype;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSettings.java b/services/core/java/com/android/server/inputmethod/InputMethodSettings.java
index a558838..7ce4074 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSettings.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSettings.java
@@ -51,8 +51,23 @@
public static final boolean DEBUG = false;
private static final String TAG = "InputMethodSettings";
- private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
- private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
+ /**
+ * An integer code that represents "no subtype" when a subtype hashcode is used.
+ *
+ * <p>Due to historical confusions with {@link InputMethodUtils#NOT_A_SUBTYPE_ID}, we have
+ * used {@code -1} here. We cannot change this value as it's already saved into secure settings.
+ * </p>
+ */
+ private static final int INVALID_SUBTYPE_HASHCODE = -1;
+ /**
+ * A string code that represents "no subtype" when a subtype hashcode is used.
+ *
+ * <p>Due to historical confusions with {@link InputMethodUtils#NOT_A_SUBTYPE_ID}, we have
+ * used {@code "-1"} here. We cannot change this value as it's already saved into secure
+ * settings.</p>
+ */
+ private static final String INVALID_SUBTYPE_HASHCODE_STR =
+ String.valueOf(INVALID_SUBTYPE_HASHCODE);
private static final char INPUT_METHOD_SEPARATOR = InputMethodUtils.INPUT_METHOD_SEPARATOR;
private static final char INPUT_METHOD_SUBTYPE_SEPARATOR =
InputMethodUtils.INPUT_METHOD_SUBTYPE_SEPARATOR;
@@ -259,34 +274,33 @@
}
private void saveSubtypeHistory(
- List<Pair<String, String>> savedImes, String newImeId, String newSubtypeId) {
+ List<Pair<String, String>> savedImes, String newImeId, String newSubtypeHashCodeStr) {
final StringBuilder builder = new StringBuilder();
boolean isImeAdded = false;
- if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeId)) {
+ if (!TextUtils.isEmpty(newImeId) && !TextUtils.isEmpty(newSubtypeHashCodeStr)) {
builder.append(newImeId).append(INPUT_METHOD_SUBTYPE_SEPARATOR).append(
- newSubtypeId);
+ newSubtypeHashCodeStr);
isImeAdded = true;
}
for (int i = 0; i < savedImes.size(); ++i) {
final Pair<String, String> ime = savedImes.get(i);
final String imeId = ime.first;
- String subtypeId = ime.second;
- if (TextUtils.isEmpty(subtypeId)) {
- subtypeId = NOT_A_SUBTYPE_ID_STR;
+ String subtypeHashCodeStr = ime.second;
+ if (TextUtils.isEmpty(subtypeHashCodeStr)) {
+ subtypeHashCodeStr = INVALID_SUBTYPE_HASHCODE_STR;
}
if (isImeAdded) {
builder.append(INPUT_METHOD_SEPARATOR);
} else {
isImeAdded = true;
}
- builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATOR).append(
- subtypeId);
+ builder.append(imeId).append(INPUT_METHOD_SUBTYPE_SEPARATOR).append(subtypeHashCodeStr);
}
// Remove the last INPUT_METHOD_SEPARATOR
putSubtypeHistoryStr(builder.toString());
}
- private void addSubtypeToHistory(String imeId, String subtypeId) {
+ private void addSubtypeToHistory(String imeId, String subtypeHashCodeStr) {
final List<Pair<String, String>> subtypeHistory = loadInputMethodAndSubtypeHistory();
for (int i = 0; i < subtypeHistory.size(); ++i) {
final Pair<String, String> ime = subtypeHistory.get(i);
@@ -301,9 +315,9 @@
}
}
if (DEBUG) {
- Slog.v(TAG, "Add subtype to the history: " + imeId + ", " + subtypeId);
+ Slog.v(TAG, "Add subtype to the history: " + imeId + ", " + subtypeHashCodeStr);
}
- saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
+ saveSubtypeHistory(subtypeHistory, imeId, subtypeHashCodeStr);
}
private void putSubtypeHistoryStr(@NonNull String str) {
@@ -413,26 +427,26 @@
for (int j = 0; j < explicitlyEnabledSubtypes.size(); ++j) {
final String s = explicitlyEnabledSubtypes.get(j);
if (s.equals(subtypeHashCode)) {
- // If both imeId and subtypeId are enabled, return subtypeId.
+ // If both imeId and subtype are enabled, return subtypeId.
try {
final int hashCode = Integer.parseInt(subtypeHashCode);
- // Check whether the subtype id is valid or not
- if (SubtypeUtils.isValidSubtypeId(imi, hashCode)) {
+ // Check whether the subtype is valid or not
+ if (SubtypeUtils.isValidSubtypeHashCode(imi, hashCode)) {
return s;
} else {
- return NOT_A_SUBTYPE_ID_STR;
+ return INVALID_SUBTYPE_HASHCODE_STR;
}
} catch (NumberFormatException e) {
- return NOT_A_SUBTYPE_ID_STR;
+ return INVALID_SUBTYPE_HASHCODE_STR;
}
}
}
}
- // If imeId was enabled but subtypeId was disabled.
- return NOT_A_SUBTYPE_ID_STR;
+ // If imeId was enabled but subtype was disabled.
+ return INVALID_SUBTYPE_HASHCODE_STR;
}
}
- // If both imeId and subtypeId are disabled, return null
+ // If both imeId and subtype are disabled, return null
return null;
}
@@ -451,14 +465,14 @@
String nextImsStr = inputMethodSplitter.next();
subtypeSplitter.setString(nextImsStr);
if (subtypeSplitter.hasNext()) {
- String subtypeId = NOT_A_SUBTYPE_ID_STR;
+ String subtypeHashCodeStr = INVALID_SUBTYPE_HASHCODE_STR;
// The first element is ime id.
String imeId = subtypeSplitter.next();
while (subtypeSplitter.hasNext()) {
- subtypeId = subtypeSplitter.next();
+ subtypeHashCodeStr = subtypeSplitter.next();
break;
}
- imsList.add(new Pair<>(imeId, subtypeId));
+ imsList.add(new Pair<>(imeId, subtypeHashCodeStr));
}
}
return imsList;
@@ -528,13 +542,8 @@
return imi;
}
- boolean isSubtypeSelected() {
- return getSelectedInputMethodSubtypeHashCode() != NOT_A_SUBTYPE_ID;
- }
-
private int getSelectedInputMethodSubtypeHashCode() {
- return getInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
- NOT_A_SUBTYPE_ID);
+ return getInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, INVALID_SUBTYPE_HASHCODE);
}
@UserIdInt
@@ -545,7 +554,7 @@
int getSelectedInputMethodSubtypeId(String selectedImiId) {
final InputMethodInfo imi = mMethodMap.get(selectedImiId);
if (imi == null) {
- return NOT_A_SUBTYPE_ID;
+ return InputMethodUtils.NOT_A_SUBTYPE_ID;
}
final int subtypeHashCode = getSelectedInputMethodSubtypeHashCode();
return SubtypeUtils.getSubtypeIdFromHashCode(imi, subtypeHashCode);
@@ -553,12 +562,12 @@
void saveCurrentInputMethodAndSubtypeToHistory(String curMethodId,
InputMethodSubtype currentSubtype) {
- String subtypeId = NOT_A_SUBTYPE_ID_STR;
+ String subtypeHashCodeStr = INVALID_SUBTYPE_HASHCODE_STR;
if (currentSubtype != null) {
- subtypeId = String.valueOf(currentSubtype.hashCode());
+ subtypeHashCodeStr = String.valueOf(currentSubtype.hashCode());
}
if (InputMethodUtils.canAddToLastInputMethod(currentSubtype)) {
- addSubtypeToHistory(curMethodId, subtypeId);
+ addSubtypeToHistory(curMethodId, subtypeHashCodeStr);
}
}
@@ -583,7 +592,7 @@
}
final int subtypeHashCode = getSelectedInputMethodSubtypeHashCode();
- if (subtypeHashCode != NOT_A_SUBTYPE_ID) {
+ if (subtypeHashCode != INVALID_SUBTYPE_HASHCODE) {
final int subtypeIndex = SubtypeUtils.getSubtypeIdFromHashCode(imi,
subtypeHashCode);
if (subtypeIndex >= 0) {
@@ -645,10 +654,10 @@
final IntArray validSubtypeHashCodes = new IntArray(subtypeHashCodes.length);
for (int subtypeHashCode : subtypeHashCodes) {
- if (subtypeHashCode == NOT_A_SUBTYPE_ID) {
- continue; // NOT_A_SUBTYPE_ID must not be saved
+ if (subtypeHashCode == INVALID_SUBTYPE_HASHCODE) {
+ continue; // INVALID_SUBTYPE_HASHCODE must not be saved
}
- if (!SubtypeUtils.isValidSubtypeId(imi, subtypeHashCode)) {
+ if (!SubtypeUtils.isValidSubtypeHashCode(imi, subtypeHashCode)) {
continue; // this subtype does not exist in InputMethodInfo.
}
if (validSubtypeHashCodes.indexOf(subtypeHashCode) >= 0) {
diff --git a/services/core/java/com/android/server/inputmethod/SubtypeUtils.java b/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
index 3d5c8677..1b4c0d6 100644
--- a/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
+++ b/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
@@ -16,9 +16,11 @@
package com.android.server.inputmethod;
+import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.LocaleList;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
@@ -100,7 +102,7 @@
return subtypes;
}
- static boolean isValidSubtypeId(InputMethodInfo imi, int subtypeHashCode) {
+ static boolean isValidSubtypeHashCode(InputMethodInfo imi, int subtypeHashCode) {
return getSubtypeIdFromHashCode(imi, subtypeHashCode) != NOT_A_SUBTYPE_ID;
}
@@ -289,4 +291,54 @@
}
return applicableSubtype;
}
+
+ /**
+ * Returns a {@link InputMethodSubtype} available in {@code imi} based on
+ * {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}.
+ *
+ * @param imi {@link InputMethodInfo} to find out the current
+ * {@link InputMethodSubtype}
+ * @param settings {@link InputMethodSettings} to be used to find out the current
+ * {@link InputMethodSubtype}
+ * @param currentSubtype the current value that will be used as fallback
+ * @return {@link InputMethodSubtype} to be used as the current {@link InputMethodSubtype}
+ */
+ @AnyThread
+ @Nullable
+ static InputMethodSubtype getCurrentInputMethodSubtype(
+ @NonNull InputMethodInfo imi, @NonNull InputMethodSettings settings,
+ @Nullable InputMethodSubtype currentSubtype) {
+ final int userId = settings.getUserId();
+ final int selectedSubtypeHashCode = SecureSettingsWrapper.getInt(
+ Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, NOT_A_SUBTYPE_ID, userId);
+ if (selectedSubtypeHashCode != NOT_A_SUBTYPE_ID && currentSubtype != null
+ && isValidSubtypeHashCode(imi, currentSubtype.hashCode())) {
+ return currentSubtype;
+ }
+
+ final int subtypeId = settings.getSelectedInputMethodSubtypeId(imi.getId());
+ if (subtypeId != NOT_A_SUBTYPE_ID) {
+ return imi.getSubtypeAt(subtypeId);
+ }
+
+ // If there are no selected subtypes, the framework will try to find the most applicable
+ // subtype from explicitly or implicitly enabled subtypes.
+ final List<InputMethodSubtype> subtypes = settings.getEnabledInputMethodSubtypeList(imi,
+ true);
+ if (subtypes.isEmpty()) {
+ return currentSubtype;
+ }
+ // If there is only one explicitly or implicitly enabled subtype,
+ // just returns it.
+ if (subtypes.size() == 1) {
+ return subtypes.get(0);
+ }
+ final String locale = SystemLocaleWrapper.get(userId).get(0).toString();
+ final var subtype = findLastResortApplicableSubtype(subtypes, SUBTYPE_MODE_KEYBOARD, locale,
+ true);
+ if (subtype != null) {
+ return subtype;
+ }
+ return findLastResortApplicableSubtype(subtypes, null, locale, true);
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f03c639..d9e22c5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -28,6 +28,7 @@
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManager.isProcStateConsideredInteraction;
import static android.app.ActivityManager.printCapabilitiesSummary;
@@ -523,6 +524,12 @@
*/
private boolean mUseMeteredFirewallChains;
+ /**
+ * Whether or not sensitive process states and non-sensitive process-states have different
+ * delays before network is blocked after transitioning to background.
+ */
+ private boolean mUseDifferentDelaysForBackgroundChain;
+
// See main javadoc for instructions on how to use these locks.
final Object mUidRulesFirstLock = new Object();
final Object mNetworkPoliciesSecondLock = new Object();
@@ -552,10 +559,43 @@
* {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} will lose network access.
* The delay is meant to prevent churn due to quick process-state changes.
* Note that there is no delay while granting network access.
+ *
+ * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is disabled.
*/
@VisibleForTesting
long mBackgroundRestrictionDelayMs = TimeUnit.SECONDS.toMillis(5);
+ /**
+ * Short delay after which a uid going into a process state having priority equal to
+ * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access.
+ *
+ * This will apply to apps that should be fine with losing network access immediately.
+ * It is only meant as a debounce to prevent churn due to quick process-state changes.
+ * Note that there is no delay while granting network access.
+ *
+ * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled.
+ */
+ @VisibleForTesting
+ long mBackgroundRestrictionShortDelayMs = TimeUnit.SECONDS.toMillis(2);
+
+ /**
+ * Long delay after which a uid going into a process state having priority equal to
+ * {@link NetworkPolicyManager#BACKGROUND_THRESHOLD_STATE} or lower will lose network access.
+ *
+ * Unlike {@link #mBackgroundRestrictionShortDelayMs}, this is meant to be applied to apps
+ * in sensitive proc-states like {@link ActivityManager#PROCESS_STATE_TOP_SLEEPING} and
+ * {@link ActivityManager#PROCESS_STATE_LAST_ACTIVITY}, where the user may switch to this app
+ * before this period and any latency in granting network access before resuming app activities
+ * may degrade experience.
+ *
+ * This is only used when the flag {@link #mUseDifferentDelaysForBackgroundChain} is enabled.
+ */
+ @VisibleForTesting
+ long mBackgroundRestrictionLongDelayMs = TimeUnit.SECONDS.toMillis(20);
+
+ @GuardedBy("mUidRulesFirstLock")
+ private long mNextProcessBackgroundUidsTime = Long.MAX_VALUE;
+
/** Defined network policies. */
@GuardedBy("mNetworkPoliciesSecondLock")
final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
@@ -1007,6 +1047,7 @@
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mUseMeteredFirewallChains = Flags.useMeteredFirewallChains();
+ mUseDifferentDelaysForBackgroundChain = Flags.useDifferentDelaysForBackgroundChain();
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
@@ -1241,11 +1282,21 @@
// different chains may change.
return true;
}
- if (mBackgroundNetworkRestricted && (previousProcState >= BACKGROUND_THRESHOLD_STATE)
+ if (mBackgroundNetworkRestricted) {
+ if ((previousProcState >= BACKGROUND_THRESHOLD_STATE)
!= (newProcState >= BACKGROUND_THRESHOLD_STATE)) {
- // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: Network rules for the
- // BACKGROUND chain may change.
- return true;
+ // Proc-state change crossed BACKGROUND_THRESHOLD_STATE: The network rules will
+ // need to be re-evaluated for the background chain.
+ return true;
+ }
+ if (mUseDifferentDelaysForBackgroundChain
+ && newProcState >= BACKGROUND_THRESHOLD_STATE
+ && getBackgroundTransitioningDelay(newProcState)
+ < getBackgroundTransitioningDelay(previousProcState)) {
+ // The old and new proc-state both are in the blocked state but the background
+ // transition delay is reduced, so we may have to update the rules sooner.
+ return true;
+ }
}
final int networkCapabilities = PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK
| PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
@@ -4045,6 +4096,8 @@
+ mBackgroundNetworkRestricted);
fout.println(Flags.FLAG_USE_METERED_FIREWALL_CHAINS + ": "
+ mUseMeteredFirewallChains);
+ fout.println(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN + ": "
+ + mUseDifferentDelaysForBackgroundChain);
fout.println();
fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -4188,20 +4241,34 @@
fout.decreaseIndent();
}
- size = mBackgroundTransitioningUids.size();
- if (size > 0) {
- final long nowUptime = SystemClock.uptimeMillis();
- fout.println("Uids transitioning to background:");
- fout.increaseIndent();
- for (int i = 0; i < size; i++) {
- fout.print("UID=");
- fout.print(mBackgroundTransitioningUids.keyAt(i));
- fout.print(", ");
- TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i), nowUptime,
- fout);
+ if (mBackgroundNetworkRestricted) {
+ fout.println();
+ if (mUseDifferentDelaysForBackgroundChain) {
+ fout.print("Background restrictions short delay: ");
+ TimeUtils.formatDuration(mBackgroundRestrictionShortDelayMs, fout);
+ fout.println();
+
+ fout.print("Background restrictions long delay: ");
+ TimeUtils.formatDuration(mBackgroundRestrictionLongDelayMs, fout);
fout.println();
}
- fout.decreaseIndent();
+
+ size = mBackgroundTransitioningUids.size();
+ if (size > 0) {
+ final long nowUptime = SystemClock.uptimeMillis();
+ fout.println("Uids transitioning to background:");
+ fout.increaseIndent();
+ for (int i = 0; i < size; i++) {
+ fout.print("UID=");
+ fout.print(mBackgroundTransitioningUids.keyAt(i));
+ fout.print(", ");
+ TimeUtils.formatDuration(mBackgroundTransitioningUids.valueAt(i),
+ nowUptime, fout);
+ fout.println();
+ }
+ fout.decreaseIndent();
+ }
+ fout.println();
}
final SparseBooleanArray knownUids = new SparseBooleanArray();
@@ -4337,6 +4404,15 @@
|| isProcStateAllowedNetworkWhileBackground(mUidState.get(uid));
}
+ private long getBackgroundTransitioningDelay(int procState) {
+ if (mUseDifferentDelaysForBackgroundChain) {
+ return procState <= PROCESS_STATE_LAST_ACTIVITY ? mBackgroundRestrictionLongDelayMs
+ : mBackgroundRestrictionShortDelayMs;
+ } else {
+ return mBackgroundRestrictionDelayMs;
+ }
+ }
+
/**
* Process state of UID changed; if needed, will trigger
* {@link #updateRulesForDataUsageRestrictionsUL(int)} and
@@ -4387,19 +4463,41 @@
mBackgroundTransitioningUids.delete(uid);
updateRuleForBackgroundUL(uid);
updatePowerRestrictionRules = true;
- } else if (wasAllowed && !isAllowed) {
+ } else if (!isAllowed) {
+ final int transitionIdx = mBackgroundTransitioningUids.indexOfKey(uid);
final long completionTimeMs = SystemClock.uptimeMillis()
- + mBackgroundRestrictionDelayMs;
- if (mBackgroundTransitioningUids.indexOfKey(uid) < 0) {
- // This is just a defensive check in case the upstream code ever makes
- // multiple calls for the same process state change.
- mBackgroundTransitioningUids.put(uid, completionTimeMs);
+ + getBackgroundTransitioningDelay(procState);
+ boolean completionTimeUpdated = false;
+ if (wasAllowed) {
+ // Rules need to transition from allowed to blocked after the respective
+ // delay.
+ if (transitionIdx < 0) {
+ // This is just a defensive check in case the upstream code ever
+ // makes multiple calls for the same process state change.
+ mBackgroundTransitioningUids.put(uid, completionTimeMs);
+ completionTimeUpdated = true;
+ }
+ } else if (mUseDifferentDelaysForBackgroundChain) {
+ // wasAllowed was false, but the transition delay may have reduced.
+ // Currently, this can happen when the uid transitions from
+ // LAST_ACTIVITY to CACHED_ACTIVITY, for example.
+ if (transitionIdx >= 0
+ && completionTimeMs < mBackgroundTransitioningUids.valueAt(
+ transitionIdx)) {
+ mBackgroundTransitioningUids.setValueAt(transitionIdx,
+ completionTimeMs);
+ completionTimeUpdated = true;
+ }
}
- if (!mHandler.hasMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS)) {
- // Many uids may be in this "transitioning" state at the same time, so
- // using one message at a time to avoid congestion in the MessageQueue.
+ if (completionTimeUpdated
+ && completionTimeMs < mNextProcessBackgroundUidsTime) {
+ // Many uids may be in this "transitioning" state at the same time,
+ // so we always keep one message to process transition completion at
+ // the earliest time.
+ mHandler.removeMessages(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS);
mHandler.sendEmptyMessageAtTime(
MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, completionTimeMs);
+ mNextProcessBackgroundUidsTime = completionTimeMs;
}
}
}
@@ -5750,10 +5848,11 @@
updateRuleForBackgroundUL(uid);
updateRulesForPowerRestrictionsUL(uid, false);
}
- }
- if (nextCheckTime < Long.MAX_VALUE) {
- mHandler.sendEmptyMessageAtTime(MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS,
- nextCheckTime);
+ mNextProcessBackgroundUidsTime = nextCheckTime;
+ if (nextCheckTime < Long.MAX_VALUE) {
+ mHandler.sendEmptyMessageAtTime(
+ MSG_PROCESS_BACKGROUND_TRANSITIONING_UIDS, nextCheckTime);
+ }
}
return true;
}
diff --git a/services/core/java/com/android/server/net/flags.aconfig b/services/core/java/com/android/server/net/flags.aconfig
index e986dd8..586baf0 100644
--- a/services/core/java/com/android/server/net/flags.aconfig
+++ b/services/core/java/com/android/server/net/flags.aconfig
@@ -17,3 +17,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "use_different_delays_for_background_chain"
+ namespace: "backstage_power"
+ description: "Grant longer grace periods for sensitive process-states before blocking network using the background chain"
+ bug: "323963467"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index cd1d799..ea71953 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -165,6 +165,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -368,18 +369,32 @@
return false;
}
+ int userId = UserHandle.getUserId(uid);
+
+ boolean isInSetup =
+ getSecureInt(Settings.Secure.USER_SETUP_COMPLETE, userId)
+ .map(setupState -> setupState == 0)
+ .orElse(false);
+ if (isInSetup) {
+ return true;
+ }
+
+ boolean isInDeferredSetup =
+ getSecureInt(Settings.Secure.USER_SETUP_PERSONALIZATION_STATE, userId)
+ .map(state ->
+ state == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED)
+ .orElse(false);
+ return isInDeferredSetup;
+ }
+
+ private Optional<Integer> getSecureInt(String settingName, int userId) {
try {
- int userId = UserHandle.getUserId(uid);
- boolean isInSetup = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_COMPLETE, userId) == 0;
- boolean isInDeferredSetup = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.USER_SETUP_PERSONALIZATION_STATE, userId)
- == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED;
- return isInSetup || isInDeferredSetup;
+ return Optional.of(
+ Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), settingName, userId));
} catch (Settings.SettingNotFoundException e) {
- Slog.w(LOG_TAG, "Failed to check if the user is in restore: " + e);
- return false;
+ Slog.i(LOG_TAG, "Setting " + settingName + " not found", e);
+ return Optional.empty();
}
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 11b9e77..80c262a 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -17,6 +17,7 @@
package com.android.server.power;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -197,9 +198,10 @@
FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
Executor backgroundExecutor, PowerManagerFlags powerManagerFlags, Injector injector) {
mContext = context;
+ mInjector = (injector == null) ? new RealInjector() : injector;
mFlags = powerManagerFlags;
mBatteryStats = batteryStats;
- mAppOps = mContext.getSystemService(AppOpsManager.class);
+ mAppOps = mInjector.getAppOpsManager(context);
mSuspendBlocker = suspendBlocker;
mPolicy = policy;
mFaceDownDetector = faceDownDetector;
@@ -230,7 +232,6 @@
mShowWirelessChargingAnimationConfig = context.getResources().getBoolean(
com.android.internal.R.bool.config_showBuiltinWirelessChargingAnim);
- mInjector = (injector == null) ? new RealInjector() : injector;
mWakeLockLog = mInjector.getWakeLockLog(context);
// Initialize interactive state for battery stats.
try {
@@ -264,6 +265,7 @@
/**
* Called when a wake lock is acquired.
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onWakeLockAcquired(int flags, String tag, String packageName,
int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
IWakeLockCallback callback) {
@@ -273,27 +275,28 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, true, ownerUid, flags);
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
- && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
- if (workSource != null) {
- mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType, unimportantForLogging);
- } else {
- mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
- monitorType, unimportantForLogging);
- // XXX need to deal with disabled operations.
- mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
- }
- } catch (RemoteException ex) {
- // Ignore
- }
- }
-
+ notifyWakeLockListener(callback, tag, true, ownerUid, ownerPid, flags, workSource,
+ packageName, historyTag);
if (!mFlags.improveWakelockLatency()) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
+ && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
+ if (workSource != null) {
+ mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType, unimportantForLogging);
+ } else {
+ mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
+ monitorType, unimportantForLogging);
+ // XXX need to deal with disabled operations.
+ mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName,
+ false, null, null);
+ }
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+ }
mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, /*eventTime=*/ -1);
}
mWakefulnessSessionObserver.onWakeLockAcquired(flags);
@@ -404,6 +407,7 @@
/**
* Called when a wake lock is released.
*/
+ @SuppressLint("AndroidFrameworkRequiresPermission")
public void onWakeLockReleased(int flags, String tag, String packageName,
int ownerUid, int ownerPid, WorkSource workSource, String historyTag,
IWakeLockCallback callback, int releaseReason) {
@@ -413,23 +417,24 @@
+ ", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+ ", workSource=" + workSource);
}
- notifyWakeLockListener(callback, tag, false, ownerUid, flags);
- final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
- if (monitorType >= 0) {
- try {
- if (workSource != null) {
- mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
- historyTag, monitorType);
- } else {
- mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
- historyTag, monitorType);
- mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
- }
- } catch (RemoteException ex) {
- // Ignore
- }
- }
+ notifyWakeLockListener(callback, tag, false, ownerUid, ownerPid, flags, workSource,
+ packageName, historyTag);
if (!mFlags.improveWakelockLatency()) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ if (workSource != null) {
+ mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType);
+ } else {
+ mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
+ historyTag, monitorType);
+ mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null);
+ }
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+ }
mWakeLockLog.onWakeLockReleased(tag, ownerUid, /*eventTime=*/ -1);
}
mWakefulnessSessionObserver.onWakeLockReleased(flags, releaseReason);
@@ -1049,24 +1054,75 @@
}
private void notifyWakeLockListener(IWakeLockCallback callback, String tag, boolean isEnabled,
- int ownerUid, int flags) {
- if (callback != null) {
- long currentTime = mInjector.currentTimeMillis();
- mHandler.post(() -> {
- try {
- if (mFlags.improveWakelockLatency()) {
+ int ownerUid, int ownerPid, int flags, WorkSource workSource, String packageName,
+ String historyTag) {
+ if (mFlags.improveWakelockLatency()) {
+ if (callback != null) {
+ long currentTime = mInjector.currentTimeMillis();
+ mHandler.post(() -> {
+ try {
if (isEnabled) {
- mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
+ notifyWakelockAcquisition(tag, ownerUid, ownerPid, flags,
+ workSource, packageName, historyTag, currentTime);
} else {
- mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
+ notifyWakelockRelease(tag, ownerUid, ownerPid, flags,
+ workSource, packageName, historyTag, currentTime);
}
+ callback.onStateChanged(isEnabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
}
- callback.onStateChanged(isEnabled);
- } catch (RemoteException e) {
- Slog.e(TAG, "Wakelock.mCallback [" + tag + "] is already dead.", e);
- }
- });
+ });
+ }
}
+
+ }
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private void notifyWakelockAcquisition(String tag, int ownerUid, int ownerPid, int flags,
+ WorkSource workSource, String packageName, String historyTag, long currentTime) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ final boolean unimportantForLogging = ownerUid == Process.SYSTEM_UID
+ && (flags & PowerManager.UNIMPORTANT_FOR_LOGGING) != 0;
+ if (workSource != null) {
+ mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType, unimportantForLogging);
+ } else {
+ mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag,
+ monitorType, unimportantForLogging);
+ // XXX need to deal with disabled operations.
+ mAppOps.startOpNoThrow(
+ AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName,
+ false, null, null);
+ }
+ } catch (RemoteException ex) {
+ // Do Nothing
+ }
+ }
+ mWakeLockLog.onWakeLockAcquired(tag, ownerUid, flags, currentTime);
+ }
+
+ @SuppressLint("AndroidFrameworkRequiresPermission")
+ private void notifyWakelockRelease(String tag, int ownerUid, int ownerPid, int flags,
+ WorkSource workSource, String packageName, String historyTag, long currentTime) {
+ final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+ if (monitorType >= 0) {
+ try {
+ if (workSource != null) {
+ mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag,
+ historyTag, monitorType);
+ } else {
+ mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag,
+ historyTag, monitorType);
+ mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName, null);
+ }
+ } catch (RemoteException ex) {
+ // Ignore
+ }
+ }
+ mWakeLockLog.onWakeLockReleased(tag, ownerUid, currentTime);
}
private final class NotifierHandler extends Handler {
@@ -1114,6 +1170,11 @@
* Gets the WakeLockLog object
*/
WakeLockLog getWakeLockLog(Context context);
+
+ /**
+ * Gets the AppOpsManager system service
+ */
+ AppOpsManager getAppOpsManager(Context context);
}
static class RealInjector implements Injector {
@@ -1126,5 +1187,10 @@
public WakeLockLog getWakeLockLog(Context context) {
return new WakeLockLog(context);
}
+
+ @Override
+ public AppOpsManager getAppOpsManager(Context context) {
+ return context.getSystemService(AppOpsManager.class);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d38cd88..15f4c8c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -156,6 +156,7 @@
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
@@ -4033,6 +4034,10 @@
if (next == null) {
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, mDisplayContent,
true /* deferResume */);
+ if (mDisplayContent.topRunningActivity() == null) {
+ // The transition is ready on a display with no running activities.
+ mTransitionController.setReady(mDisplayContent);
+ }
}
if (activityRemoved) {
mRootWindowContainer.resumeFocusedTasksTopActivities();
@@ -6028,14 +6033,7 @@
true /* activityChange */, true /* updateOomAdj */,
true /* addPendingTopUid */);
}
- final ContentCaptureManagerInternal contentCaptureService =
- LocalServices.getService(ContentCaptureManagerInternal.class);
- if (contentCaptureService != null) {
- contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
- ActivityEvent.TYPE_ACTIVITY_STARTED,
- new ActivityId(getTask() != null ? getTask().mTaskId : INVALID_TASK_ID,
- shareableActivityToken));
- }
+ mAtmService.mH.post(this::notifyActivityStartedToContentCaptureService);
break;
case PAUSED:
mAtmService.updateBatteryStats(this, false);
@@ -6067,6 +6065,22 @@
}
}
+ private void notifyActivityStartedToContentCaptureService() {
+ final ContentCaptureManagerInternal contentCaptureService =
+ LocalServices.getService(ContentCaptureManagerInternal.class);
+ if (contentCaptureService != null) {
+ // For ACTIVITY_STARTED content capture is directly invoked to avoid persisting
+ // to UsageStats.
+ contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
+ ActivityEvent.TYPE_ACTIVITY_STARTED,
+ new ActivityId(getTask() != null ? getTask().mTaskId : INVALID_TASK_ID,
+ shareableActivityToken));
+
+ contentCaptureService.sendActivityStartAssistData(mUserId,
+ shareableActivityToken, intent);
+ }
+ }
+
State getState() {
return mState;
}
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 0978cb4..a21ba26 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -77,12 +77,14 @@
mWindows.put(inputToken, window);
final InputTransferToken inputTransferToken = window.getInputTransferToken();
mWindowsByInputTransferToken.put(inputTransferToken, window);
- mWindowsByWindowToken.put(window.getWindowToken(), window);
+ final IBinder windowToken = window.getWindowToken();
+ mWindowsByWindowToken.put(windowToken, window);
updateProcessController(window);
window.mClient.linkToDeath(()-> {
synchronized (mGlobalLock) {
mWindows.remove(inputToken);
mWindowsByInputTransferToken.remove(inputTransferToken);
+ mWindowsByWindowToken.remove(windowToken);
}
}, 0);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 1cc1a57..7510180 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -157,7 +157,7 @@
// home & recent tasks
return;
}
- if (task.isVisible()) {
+ if (task.isVisibleRequested()) {
mTmpVisibleTasks.add(task);
} else {
mTmpInvisibleTasks.add(task);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c02a437..22f718d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4786,6 +4786,12 @@
if (com.android.window.flags.Flags.removePrepareSurfaceInPlacement()
&& lastParentBeforePip.mSyncState == SYNC_STATE_NONE) {
lastParentBeforePip.prepareSurfaces();
+ // If the moveToFront is a part of finishing transition, then make sure
+ // the z-order of tasks are up-to-date.
+ if (topActivity.mTransitionController.inFinishingTransition(topActivity)) {
+ Transition.assignLayers(taskDisplayArea,
+ taskDisplayArea.getPendingTransaction());
+ }
}
}
if (isPip2ExperimentEnabled) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4aa3e36..63ca469 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1048,7 +1048,7 @@
// the animation played. This puts the layers back into the correct order.
for (int i = displays.size() - 1; i >= 0; --i) {
if (displays.valueAt(i) == null) continue;
- updateDisplayLayers(displays.valueAt(i), t);
+ assignLayers(displays.valueAt(i), t);
}
for (int i = 0; i < info.getRootCount(); ++i) {
@@ -1056,12 +1056,13 @@
}
}
- private static void updateDisplayLayers(DisplayContent dc, SurfaceControl.Transaction t) {
- dc.mTransitionController.mBuildingFinishLayers = true;
+ /** Assigns the layers for the start or end state of transition. */
+ static void assignLayers(WindowContainer<?> wc, SurfaceControl.Transaction t) {
+ wc.mTransitionController.mBuildingFinishLayers = true;
try {
- dc.assignChildLayers(t);
+ wc.assignChildLayers(t);
} finally {
- dc.mTransitionController.mBuildingFinishLayers = false;
+ wc.mTransitionController.mBuildingFinishLayers = false;
}
}
@@ -2717,7 +2718,7 @@
rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots");
// Update layers to start transaction because we prevent assignment during collect, so
// the layer of transition root can be correct.
- updateDisplayLayers(dc, startT);
+ assignLayers(dc, startT);
startT.setLayer(rootLeash, leashReference.getLastLayer());
outInfo.addRootLeash(endDisplayId, rootLeash,
ancestor.getBounds().left, ancestor.getBounds().top);
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index 957d7c3..ce05c82 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -66,7 +66,6 @@
"libprotobuf-cpp-lite",
"service.incremental.proto",
"libvold_binder",
- "libc++fs",
"libziparchive_for_incfs",
],
shared_libs: [
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cfe4e17..107c294 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1196,11 +1196,12 @@
mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
t.traceEnd();
+ // Initialize RescueParty.
+ RescueParty.registerHealthObserver(mSystemContext);
if (!Flags.recoverabilityDetection()) {
// Now that we have the bare essentials of the OS up and running, take
// note that we just booted, which might send out a rescue party if
// we're stuck in a runtime restart loop.
- RescueParty.registerHealthObserver(mSystemContext);
PackageWatchdog.getInstance(mSystemContext).noteBoot();
}
@@ -2917,10 +2918,10 @@
t.traceEnd();
if (Flags.recoverabilityDetection()) {
- // Now that we have the essential services needed for rescue party, initialize
- // RescuParty. note that we just booted, which might send out a rescue party if
- // we're stuck in a runtime restart loop.
- RescueParty.registerHealthObserver(mSystemContext);
+ // Now that we have the essential services needed for mitigations, register the boot
+ // with package watchdog.
+ // Note that we just booted, which might send out a rescue party if we're stuck in a
+ // runtime restart loop.
PackageWatchdog.getInstance(mSystemContext).noteBoot();
}
diff --git a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
index 6499556..78dbc60 100644
--- a/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/PermissionService.kt
@@ -533,8 +533,7 @@
val packageState =
packageManagerLocal.withFilteredSnapshot(Binder.getCallingUid(), userId).use {
it.getPackageState(packageName)
- }
- ?: return PackageManager.PERMISSION_DENIED
+ } ?: return PackageManager.PERMISSION_DENIED
val isPermissionGranted =
service.getState { isPermissionGranted(packageState, userId, permissionName, deviceId) }
@@ -1164,8 +1163,7 @@
val packageState =
packageManagerLocal.withFilteredSnapshot(Binder.getCallingUid(), userId).use {
it.getPackageState(packageName)
- }
- ?: return false
+ } ?: return false
service.getState {
if (isPermissionGranted(packageState, userId, permissionName, deviceId)) {
@@ -1216,8 +1214,7 @@
val packageState =
packageManagerLocal.withFilteredSnapshot(callingUid, userId).use {
it.getPackageState(packageName)
- }
- ?: return false
+ } ?: return false
val appId = packageState.appId
if (UserHandle.getAppId(callingUid) != appId) {
return false
@@ -1546,8 +1543,7 @@
val packageState =
packageManagerLocal.withFilteredSnapshot(callingUid, userId).use {
it.getPackageState(packageName)
- }
- ?: return null
+ } ?: return null
val androidPackage = packageState.androidPackage ?: return null
val isCallerPrivileged =
@@ -1710,8 +1706,7 @@
PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER,
userId
)
- ?.let { ArraySet(permissionNames).apply { this += it }.toList() }
- ?: permissionNames
+ ?.let { ArraySet(permissionNames).apply { this += it }.toList() } ?: permissionNames
setAllowlistedRestrictedPermissionsUnchecked(
androidPackage,
@@ -2753,27 +2748,25 @@
) {
return false
}
- return try {
- val contentResolver = context.contentResolver
- val userId = UserHandle.getUserId(uid)
- val isInSetup =
- Settings.Secure.getIntForUser(
- contentResolver,
- Settings.Secure.USER_SETUP_COMPLETE,
- userId
- ) == 0
- val isInDeferredSetup =
- Settings.Secure.getIntForUser(
- contentResolver,
- Settings.Secure.USER_SETUP_PERSONALIZATION_STATE,
- userId
- ) == Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED
- isInSetup || isInDeferredSetup
- } catch (e: Settings.SettingNotFoundException) {
- Slog.w(LOG_TAG, "Failed to check if the user is in restore: $e")
- false
- }
+
+ val userId = UserHandle.getUserId(uid)
+
+ val isInSetup = getSecureInt(Settings.Secure.USER_SETUP_COMPLETE, userId) == 0
+ if (isInSetup) return true
+
+ val isInDeferredSetup =
+ getSecureInt(Settings.Secure.USER_SETUP_PERSONALIZATION_STATE, userId) ==
+ Settings.Secure.USER_SETUP_PERSONALIZATION_STARTED
+ return isInDeferredSetup
}
+
+ private fun getSecureInt(settingName: String, userId: Int): Int? =
+ try {
+ Settings.Secure.getIntForUser(context.contentResolver, settingName, userId)
+ } catch (e: Settings.SettingNotFoundException) {
+ Slog.i(LOG_TAG, "Setting $settingName not found", e)
+ null
+ }
}
private class OnPermissionsChangeListeners(looper: Looper) : Handler(looper) {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index d0eb83a..211ab03 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -2569,6 +2569,63 @@
}
@Test
+ public void testPowerOnAndOffInternalDisplay() {
+ manageDisplaysPermission(/* granted= */ true);
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+ LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
+ FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+ bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+
+ callback.expectsEvent(EVENT_DISPLAY_ADDED);
+ FakeDisplayDevice displayDevice =
+ createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+ callback.waitForExpectedEvent();
+
+ LogicalDisplay display =
+ logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_ON);
+
+ assertThat(displayManager.requestDisplayPower(display.getDisplayIdLocked(), false))
+ .isTrue();
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_OFF);
+
+ assertThat(displayManager.requestDisplayPower(display.getDisplayIdLocked(), true))
+ .isTrue();
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_ON);
+ }
+
+ @Test
+ public void testPowerOnAndOffInternalDisplay_withoutPermission_shouldThrowException() {
+ DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+ DisplayManagerService.BinderService bs = displayManager.new BinderService();
+ LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper();
+ FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback();
+ bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS);
+
+ callback.expectsEvent(EVENT_DISPLAY_ADDED);
+ FakeDisplayDevice displayDevice =
+ createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+ callback.waitForExpectedEvent();
+
+ LogicalDisplay display =
+ logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true);
+ var displayId = display.getDisplayIdLocked();
+
+ assertThat(displayDevice.getDisplayDeviceInfoLocked().committedState)
+ .isEqualTo(Display.STATE_ON);
+
+ assertThrows(SecurityException.class, () -> bs.requestDisplayPower(displayId, true));
+ assertThrows(SecurityException.class, () -> bs.requestDisplayPower(displayId, false));
+ }
+
+ @Test
public void testEnableExternalDisplay_withDisplayManagement_shouldSignalDisplayAdded() {
when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true);
manageDisplaysPermission(/* granted= */ true);
@@ -3529,6 +3586,7 @@
public void setDisplayDeviceInfo(DisplayDeviceInfo displayDeviceInfo) {
mDisplayDeviceInfo = displayDeviceInfo;
+ mDisplayDeviceInfo.committedState = Display.STATE_ON;
}
@Override
@@ -3558,5 +3616,14 @@
public Display.Mode getUserPreferredDisplayModeLocked() {
return mPreferredMode;
}
+
+ @Override
+ public Runnable requestDisplayStateLocked(
+ final int state,
+ final float brightnessState,
+ final float sdrBrightnessState,
+ @Nullable DisplayOffloadSessionImpl displayOffloadSession) {
+ return () -> mDisplayDeviceInfo.committedState = state;
+ }
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 28c7fb2..488ce66 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -44,6 +44,7 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.android.server.am.ActivityManagerService.FOLLOW_UP_OOMADJUSTER_UPDATE_MSG;
import static com.android.server.am.ProcessList.BACKUP_APP_ADJ;
import static com.android.server.am.ProcessList.CACHED_APP_MAX_ADJ;
import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
@@ -77,6 +78,7 @@
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doNothing;
@@ -113,11 +115,10 @@
import com.android.server.wm.WindowProcessController;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import java.io.File;
import java.lang.reflect.Field;
@@ -164,92 +165,86 @@
private static int sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ
+ ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- private static Context sContext;
- private static PackageManagerInternal sPackageManagerInternal;
- private static ActivityManagerService sService;
+ private Context mContext;
+ private PackageManagerInternal mPackageManagerInternal;
+ private ActivityManagerService mService;
+ private OomAdjusterInjector mInjector = new OomAdjusterInjector();
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@SuppressWarnings("GuardedBy")
- @BeforeClass
- public static void setUpOnce() {
- sContext = getInstrumentation().getTargetContext();
+ @Before
+ public void setUp() {
+ mContext = getInstrumentation().getTargetContext();
System.setProperty("dexmaker.share_classloader", "true");
- sPackageManagerInternal = mock(PackageManagerInternal.class);
- doReturn(new ComponentName("", "")).when(sPackageManagerInternal)
+ mPackageManagerInternal = mock(PackageManagerInternal.class);
+ doReturn(new ComponentName("", "")).when(mPackageManagerInternal)
.getSystemUiServiceComponent();
// Remove stale instance of PackageManagerInternal if there is any
LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal);
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
- sService = mock(ActivityManagerService.class);
- sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
- sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
- sService.mPackageManagerInt = sPackageManagerInternal;
- sService.mAtmInternal = spy(sService.mActivityTaskManager.getAtmInternal());
+ mService = mock(ActivityManagerService.class);
+ mService.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+ mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
+ mService.mPackageManagerInt = mPackageManagerInternal;
+ mService.mAtmInternal = spy(mService.mActivityTaskManager.getAtmInternal());
- sService.mConstants = new ActivityManagerConstants(sContext, sService,
- sContext.getMainThreadHandler());
- setFieldValue(ActivityManagerService.class, sService, "mContext",
- sContext);
+ mService.mConstants = new ActivityManagerConstants(mContext, mService,
+ mContext.getMainThreadHandler());
+ setFieldValue(ActivityManagerService.class, mService, "mContext",
+ mContext);
ProcessList pr = spy(new ProcessList());
- pr.mService = sService;
+ pr.mService = mService;
AppProfiler profiler = mock(AppProfiler.class);
- setFieldValue(ActivityManagerService.class, sService, "mProcessList",
+ setFieldValue(ActivityManagerService.class, mService, "mProcessList",
pr);
- setFieldValue(ActivityManagerService.class, sService, "mHandler",
+ setFieldValue(ActivityManagerService.class, mService, "mHandler",
mock(ActivityManagerService.MainHandler.class));
- setFieldValue(ActivityManagerService.class, sService, "mProcessStats",
- new ProcessStatsService(sService, new File(sContext.getFilesDir(), "procstats")));
- setFieldValue(ActivityManagerService.class, sService, "mBackupTargets",
+ setFieldValue(ActivityManagerService.class, mService, "mProcessStats",
+ new ProcessStatsService(mService, new File(mContext.getFilesDir(), "procstats")));
+ setFieldValue(ActivityManagerService.class, mService, "mBackupTargets",
mock(SparseArray.class));
- setFieldValue(ActivityManagerService.class, sService, "mUserController",
+ setFieldValue(ActivityManagerService.class, mService, "mUserController",
mock(UserController.class));
- setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler);
- setFieldValue(ActivityManagerService.class, sService, "mProcLock",
+ setFieldValue(ActivityManagerService.class, mService, "mAppProfiler", profiler);
+ setFieldValue(ActivityManagerService.class, mService, "mProcLock",
new ActivityManagerProcLock());
- setFieldValue(ActivityManagerService.class, sService, "mServices",
- spy(new ActiveServices(sService)));
- setFieldValue(ActivityManagerService.class, sService, "mInternal",
+ setFieldValue(ActivityManagerService.class, mService, "mServices",
+ spy(new ActiveServices(mService)));
+ setFieldValue(ActivityManagerService.class, mService, "mInternal",
mock(ActivityManagerService.LocalService.class));
- setFieldValue(ActivityManagerService.class, sService, "mBatteryStatsService",
+ setFieldValue(ActivityManagerService.class, mService, "mBatteryStatsService",
mock(BatteryStatsService.class));
- setFieldValue(ActivityManagerService.class, sService, "mInjector",
- new ActivityManagerService.Injector(sContext));
- doReturn(mock(AppOpsManager.class)).when(sService).getAppOpsManager();
- doCallRealMethod().when(sService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
- doCallRealMethod().when(sService).updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_ACTIVITY);
+ setFieldValue(ActivityManagerService.class, mService, "mInjector",
+ new ActivityManagerService.Injector(mContext));
+ doReturn(mock(AppOpsManager.class)).when(mService).getAppOpsManager();
+ doCallRealMethod().when(mService).enqueueOomAdjTargetLocked(any(ProcessRecord.class));
+ doCallRealMethod().when(mService).updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_ACTIVITY);
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
doReturn(new ActivityManagerService.ProcessChangeItem()).when(pr)
.enqueueProcessChangeItemLocked(anyInt(), anyInt());
- sService.mOomAdjuster = sService.mConstants.ENABLE_NEW_OOMADJ
- ? new OomAdjusterModernImpl(sService, sService.mProcessList,
- new ActiveUids(sService, false))
- : new OomAdjuster(sService, sService.mProcessList, new ActiveUids(sService, false));
- sService.mOomAdjuster.mAdjSeq = 10000;
- sService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
- if (sService.mConstants.USE_TIERED_CACHED_ADJ) {
+ mService.mOomAdjuster = mService.mConstants.ENABLE_NEW_OOMADJ
+ ? new OomAdjusterModernImpl(mService, mService.mProcessList,
+ new ActiveUids(mService, false), mInjector)
+ : new OomAdjuster(mService, mService.mProcessList, new ActiveUids(mService, false),
+ mInjector);
+ mService.mOomAdjuster.mAdjSeq = 10000;
+ mService.mWakefulness = new AtomicInteger(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ if (mService.mConstants.USE_TIERED_CACHED_ADJ) {
sFirstCachedAdj = ProcessList.CACHED_APP_MIN_ADJ + 10;
}
- }
-
- @Before
- public void setUp() {
mSetFlagsRule.enableFlags(Flags.FLAG_NEW_FGS_RESTRICTION_LOGIC);
}
- @AfterClass
- public static void tearDownOnce() {
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- }
-
@SuppressWarnings("GuardedBy")
@After
public void tearDown() {
- sService.mOomAdjuster.resetInternal();
- sService.mOomAdjuster.mActiveUids.clear();
+ mService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.mActiveUids.clear();
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
}
private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
@@ -278,7 +273,7 @@
*/
@SuppressWarnings("GuardedBy")
private void setProcessesToLru(ProcessRecord... apps) {
- ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
+ ArrayList<ProcessRecord> lru = mService.mProcessList.getLruProcessesLOSP();
lru.clear();
Collections.addAll(lru, apps);
}
@@ -292,20 +287,20 @@
@SuppressWarnings("GuardedBy")
private void updateOomAdj(ProcessRecord... apps) {
if (apps.length == 0) {
- updateProcessRecordNodes(sService.mProcessList.getLruProcessesLOSP());
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateProcessRecordNodes(mService.mProcessList.getLruProcessesLOSP());
+ mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
} else {
updateProcessRecordNodes(Arrays.asList(apps));
if (apps.length == 1) {
final ProcessRecord app = apps[0];
- if (!sService.mProcessList.getLruProcessesLOSP().contains(app)) {
- sService.mProcessList.getLruProcessesLOSP().add(app);
+ if (!mService.mProcessList.getLruProcessesLOSP().contains(app)) {
+ mService.mProcessList.getLruProcessesLOSP().add(app);
}
- sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
+ mService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
} else {
setProcessesToLru(apps);
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
- sService.mProcessList.getLruProcessesLOSP().clear();
+ mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ mService.mProcessList.getLruProcessesLOSP().clear();
}
}
}
@@ -318,10 +313,10 @@
private void updateOomAdjPending(ProcessRecord... apps) {
setProcessesToLru(apps);
for (ProcessRecord app : apps) {
- sService.mOomAdjuster.enqueueOomAdjTargetLocked(app);
+ mService.mOomAdjuster.enqueueOomAdjTargetLocked(app);
}
- sService.mOomAdjuster.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_NONE);
- sService.mProcessList.getLruProcessesLOSP().clear();
+ mService.mOomAdjuster.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_NONE);
+ mService.mProcessList.getLruProcessesLOSP().clear();
}
/**
@@ -343,9 +338,9 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app.mState.setHasTopUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(app);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERSISTENT_PROC_ADJ,
SCHED_GROUP_RESTRICTED);
@@ -359,7 +354,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app.mState.setHasTopUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
@@ -372,10 +367,10 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_PERSISTENT_UI, PERSISTENT_PROC_ADJ,
SCHED_GROUP_TOP_APP);
@@ -386,11 +381,11 @@
public void testUpdateOomAdj_DoOne_TopApp_Awake() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_TOP_APP);
}
@@ -400,11 +395,11 @@
public void testUpdateOomAdj_DoOne_RunningAnimations() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
+ doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
app.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP);
}
@@ -415,7 +410,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
doReturn(mock(ActiveInstrumentation.class)).when(app).getActiveInstrumentation();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doCallRealMethod().when(app).getActiveInstrumentation();
@@ -429,11 +424,11 @@
public void testUpdateOomAdj_DoOne_ReceivingBroadcast() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(true).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
+ doReturn(true).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(int[].class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(false).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
+ doReturn(false).when(mService).isReceivingBroadcastLocked(any(ProcessRecord.class),
any(int[].class));
assertProcStates(app, PROCESS_STATE_RECEIVER, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -445,7 +440,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.startExecutingService(mock(ServiceRecord.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -456,13 +451,13 @@
public void testUpdateOomAdj_DoOne_TopApp_Sleeping() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP_SLEEPING).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ doReturn(PROCESS_STATE_TOP_SLEEPING).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(app);
- doReturn(null).when(sService).getTopApp();
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(null).when(mService).getTopApp();
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
assertProcStates(app, PROCESS_STATE_TOP_SLEEPING, FOREGROUND_APP_ADJ,
SCHED_GROUP_BACKGROUND);
@@ -475,8 +470,8 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setCurRawAdj(CACHED_APP_MIN_ADJ);
app.mState.setCurAdj(CACHED_APP_MIN_ADJ);
- doReturn(null).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(null).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
final int expectedAdj = sFirstCachedAdj;
@@ -505,7 +500,7 @@
return 0;
})).when(wpc).computeOomAdjFromActivities(
any(WindowProcessController.ComputeOomAdjCallback.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_TOP_APP);
@@ -522,7 +517,7 @@
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).hasRecentTasks();
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doCallRealMethod().when(wpc).hasRecentTasks();
@@ -536,7 +531,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasForegroundServices(true, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION,
/* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -550,7 +545,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -561,10 +556,10 @@
@SuppressWarnings("GuardedBy")
@Test
public void testUpdateOomAdj_DoOne_FgService_ShortFgs() {
- sService.mConstants.TOP_TO_FGS_GRACE_DURATION = 100_000;
- sService.mConstants.mShortFgsProcStateExtraWaitDuration = 200_000;
+ mService.mConstants.TOP_TO_FGS_GRACE_DURATION = 100_000;
+ mService.mConstants.mShortFgsProcStateExtraWaitDuration = 200_000;
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -579,7 +574,7 @@
app.mServices.setHasForegroundServices(true,
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -596,8 +591,8 @@
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
app.mServices.startService(s);
app.mState.setLastTopTime(SystemClock.uptimeMillis()
- - sService.mConstants.TOP_TO_FGS_GRACE_DURATION);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ - mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -607,14 +602,14 @@
}
// SHORT_SERVICE, timed out already.
- s = ServiceRecord.newEmptyInstanceForTest(sService);
+ s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
s.setShortFgsInfo(SystemClock.uptimeMillis()
- - sService.mConstants.mShortFgsTimeoutDuration
- - sService.mConstants.mShortFgsProcStateExtraWaitDuration);
+ - mService.mConstants.mShortFgsTimeoutDuration
+ - mService.mConstants.mShortFgsProcStateExtraWaitDuration);
{
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
@@ -622,8 +617,8 @@
FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
app.mServices.startService(s);
app.mState.setLastTopTime(SystemClock.uptimeMillis()
- - sService.mConstants.TOP_TO_FGS_GRACE_DURATION);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ - mService.mConstants.TOP_TO_FGS_GRACE_DURATION);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -639,7 +634,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setHasOverlayUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, PERCEPTIBLE_APP_ADJ,
@@ -653,12 +648,26 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
app.mState.setLastTopTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE,
- PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
+ PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT, "fg-service-act");
assertBfsl(app);
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT, "fg-service");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
}
@SuppressWarnings("GuardedBy")
@@ -678,12 +687,24 @@
s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertEquals(sFirstCachedAdj, app.mState.getSetAdj());
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+
}
// Out of grace period but valid binding allows the adjustment.
@@ -698,14 +719,14 @@
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE + 2, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
- nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+ nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
// Out of grace period and no valid binding so no adjustment.
@@ -720,15 +741,15 @@
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
- nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
+ nowUptime - 2 * mService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertNotEquals(PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
}
@@ -744,7 +765,7 @@
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(system, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -757,7 +778,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mState.setForcingToImportant(new Object());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -771,7 +792,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHeavyWeightProcess();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
doReturn(false).when(wpc).isHeavyWeightProcess();
@@ -786,7 +807,7 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isHomeProcess();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_HOME, HOME_APP_ADJ, SCHED_GROUP_BACKGROUND);
@@ -800,11 +821,25 @@
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).isPreviousProcess();
doReturn(true).when(wpc).hasActivities();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
- SCHED_GROUP_BACKGROUND);
+ SCHED_GROUP_BACKGROUND, "previous");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, CACHED_APP_MIN_ADJ,
+ SCHED_GROUP_BACKGROUND, "previous-expired");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
}
@SuppressWarnings("GuardedBy")
@@ -814,10 +849,10 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
backupTarget.app = app;
- doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
- doReturn(null).when(sService.mBackupTargets).get(anyInt());
+ doReturn(null).when(mService.mBackupTargets).get(anyInt());
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, BACKUP_APP_ADJ,
SCHED_GROUP_BACKGROUND);
@@ -829,7 +864,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setHasClientActivities(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY_CLIENT, app.mState.getSetProcState());
@@ -841,7 +876,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
app.mServices.setTreatLikeActivity(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -858,7 +893,7 @@
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
app.mServices.startService(s);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_B_ADJ, SCHED_GROUP_BACKGROUND);
@@ -870,7 +905,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.mState.setMaxAdj(PERCEPTIBLE_LOW_APP_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, PERCEPTIBLE_LOW_APP_ADJ,
@@ -884,8 +919,8 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.mState.setCurRawAdj(SERVICE_ADJ);
app.mState.setCurAdj(SERVICE_ADJ);
- doReturn(null).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(null).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertTrue(ProcessList.CACHED_APP_MIN_ADJ <= app.mState.getSetAdj());
@@ -902,7 +937,7 @@
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
app.mServices.startService(s);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -918,11 +953,11 @@
ServiceRecord s = bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY,
mock(IBinder.class));
s.startRequested = true;
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_SERVICE, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
}
@@ -937,7 +972,7 @@
client.mServices.setTreatLikeActivity(true);
bindService(app, client, null, null, Context.BIND_WAIVE_PRIORITY
| Context.BIND_TREAT_LIKE_ACTIVITY, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_CACHED_ACTIVITY, app.mState.getSetProcState());
@@ -956,9 +991,9 @@
ConnectionRecord cr = s.getConnections().get(binder).get(0);
setFieldValue(ConnectionRecord.class, cr, "activity",
mock(ActivityServiceConnectionsHolder.class));
- doReturn(client).when(sService).getTopApp();
+ doReturn(client).when(mService).getTopApp();
doReturn(true).when(cr.activity).isActivityVisible();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -971,7 +1006,7 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
bindService(app, app, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
@@ -986,7 +1021,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.mServices.setTreatLikeActivity(true);
bindService(app, client, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_CACHED_EMPTY, app.mState.getSetProcState());
@@ -1005,11 +1040,11 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_ALLOW_OOM_MANAGEMENT,
mock(IBinder.class));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertEquals(PREVIOUS_APP_ADJ, app.mState.getSetAdj());
}
@@ -1024,7 +1059,7 @@
bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
client.mState.setHasTopUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1041,7 +1076,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_IMPORTANT, mock(IBinder.class));
client.mServices.startExecutingService(mock(ServiceRecord.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -1056,11 +1091,11 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ, SCHED_GROUP_DEFAULT);
}
@@ -1074,7 +1109,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_FOREGROUND_SERVICE, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_BOUND_FOREGROUND_SERVICE, app.mState.getSetProcState());
@@ -1092,7 +1127,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_FOREGROUND, mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_TRANSIENT_BACKGROUND, app.mState.getSetProcState());
@@ -1108,7 +1143,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_FOREGROUND_SERVICE, client.mState.getSetProcState());
@@ -1128,7 +1163,7 @@
bindService(app, client, null, null, 0, mock(IBinder.class));
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -1139,7 +1174,7 @@
client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
/* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1159,7 +1194,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -1170,7 +1205,7 @@
app2.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
/* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app2);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1211,11 +1246,11 @@
bindService(app, client, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class));
BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0);
backupTarget.app = client;
- doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt());
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService.mBackupTargets).get(anyInt());
+ doReturn(null).when(mService.mBackupTargets).get(anyInt());
assertEquals(BACKUP_APP_ADJ, app.mState.getSetAdj());
assertNoBfsl(app);
@@ -1236,7 +1271,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_LOW_APP_ADJ, app.mState.getSetAdj());
@@ -1251,7 +1286,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, Context.BIND_NOT_VISIBLE, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1266,7 +1301,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
client.mState.setHasOverlayUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1284,12 +1319,12 @@
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
{
@@ -1303,13 +1338,13 @@
Context.BIND_ALMOST_PERCEPTIBLE | Context.BIND_NOT_FOREGROUND,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ + 2, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
{
@@ -1321,12 +1356,12 @@
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
{
@@ -1340,13 +1375,13 @@
Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
doReturn(false).when(wpc).isHeavyWeightProcess();
assertEquals(PERCEPTIBLE_APP_ADJ + 1, app.mState.getSetAdj());
- sService.mOomAdjuster.resetInternal();
+ mService.mOomAdjuster.resetInternal();
}
}
@@ -1359,7 +1394,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindService(app, client, null, null, 0, mock(IBinder.class));
client.mState.setRunningRemoteAnimation(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(VISIBLE_APP_ADJ, app.mState.getSetAdj());
@@ -1375,7 +1410,7 @@
bindService(app, client, null, null, Context.BIND_IMPORTANT_BACKGROUND,
mock(IBinder.class));
client.mState.setHasOverlayUi(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertEquals(PROCESS_STATE_IMPORTANT_BACKGROUND, app.mState.getSetProcState());
@@ -1402,7 +1437,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, false);
client.mServices.setTreatLikeActivity(true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND);
@@ -1416,11 +1451,11 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, false);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
}
@@ -1434,7 +1469,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindProvider(app, client, null, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1452,7 +1487,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
- ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
@@ -1464,7 +1499,7 @@
client.mServices.setHasForegroundServices(true, FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
/* hasNoneType=*/false);
bindProvider(app, client, null, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
// Client only has a SHORT_FGS, so it doesn't have BFSL, and that's propagated.
@@ -1486,7 +1521,7 @@
ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
bindProvider(app, client, null, null, true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, app);
assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND, FOREGROUND_APP_ADJ,
@@ -1499,11 +1534,25 @@
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
- SCHED_GROUP_BACKGROUND);
+ SCHED_GROUP_BACKGROUND, "recent-provider");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-empty");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
}
@SuppressWarnings("GuardedBy")
@@ -1517,11 +1566,11 @@
ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client2).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client2).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
- doReturn(null).when(sService).getTopApp();
+ doReturn(null).when(mService).getTopApp();
assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
@@ -1539,7 +1588,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(app, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1559,7 +1608,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client, client2, null, null, 0, mock(IBinder.class));
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1584,7 +1633,7 @@
// Note: We add processes to LRU but still call updateOomAdjLocked() with a specific
// processes.
setProcessesToLru(app, client, client2);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1598,7 +1647,7 @@
assertBfsl(client2);
client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client2);
assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.mState.getSetProcState());
@@ -1622,7 +1671,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindService(client2, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1649,7 +1698,7 @@
bindService(client, client2, null, null, 0, mock(IBinder.class));
bindService(client2, client, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1683,7 +1732,7 @@
bindService(client3, client4, null, null, 0, mock(IBinder.class));
bindService(client4, client3, null, null, 0, mock(IBinder.class));
client.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1720,7 +1769,7 @@
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1746,7 +1795,7 @@
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1773,7 +1822,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.mState.setForcingToImportant(new Object());
bindService(app, client4, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -1802,7 +1851,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
client4.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, client4, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3, client4);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1828,7 +1877,7 @@
MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
client3.mState.setForcingToImportant(new Object());
bindService(app, client3, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, client3, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1848,7 +1897,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1869,7 +1918,7 @@
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(client2, app, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1889,7 +1938,7 @@
MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client, client2, app);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1910,7 +1959,7 @@
bindProvider(client, client2, null, null, false);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindProvider(client2, app, null, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -1936,7 +1985,7 @@
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
client2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
@@ -1957,7 +2006,7 @@
assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
updateOomAdj(client1, client2, app1, app2);
assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
SCHED_GROUP_TOP_APP);
@@ -2028,9 +2077,9 @@
SCHED_GROUP_DEFAULT);
client2.mState.setHasOverlayUi(false);
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(client2).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(client2).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(client2, app2);
assertProcStates(app2, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
@@ -2047,7 +2096,7 @@
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
bindService(app1, client1, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class));
@@ -2068,7 +2117,7 @@
client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
app1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
bindService(app1, client1, null, null, Context.BIND_ALMOST_PERCEPTIBLE,
mock(IBinder.class));
@@ -2088,7 +2137,7 @@
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(false);
- sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_CACHED_EMPTY, FOREGROUND_APP_ADJ,
@@ -2102,9 +2151,9 @@
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(true);
- doReturn(app).when(sService).getTopApp();
+ doReturn(app).when(mService).getTopApp();
- sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
+ mService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ,
@@ -2124,10 +2173,10 @@
MOCKAPP4_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
final ProcessRecord app3 = spy(makeDefaultProcessRecord(MOCKAPP5_PID, MOCKAPP5_UID,
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
- final UidRecord app1UidRecord = new UidRecord(MOCKAPP_UID, sService);
- final UidRecord app2UidRecord = new UidRecord(MOCKAPP2_UID, sService);
- final UidRecord app3UidRecord = new UidRecord(MOCKAPP5_UID, sService);
- final UidRecord clientUidRecord = new UidRecord(MOCKAPP3_UID, sService);
+ final UidRecord app1UidRecord = new UidRecord(MOCKAPP_UID, mService);
+ final UidRecord app2UidRecord = new UidRecord(MOCKAPP2_UID, mService);
+ final UidRecord app3UidRecord = new UidRecord(MOCKAPP5_UID, mService);
+ final UidRecord clientUidRecord = new UidRecord(MOCKAPP3_UID, mService);
app1.setUidRecord(app1UidRecord);
app2.setUidRecord(app2UidRecord);
app3.setUidRecord(app3UidRecord);
@@ -2137,7 +2186,7 @@
client1.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
client2.mState.setForcingToImportant(new Object());
setProcessesToLru(app1, app2, app3, client1, client2);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
final ComponentName cn1 = ComponentName.unflattenFromString(
MOCKAPP_PACKAGENAME + "/.TestService");
@@ -2164,10 +2213,10 @@
c2s.startRequested = true;
try {
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP_UID, app1UidRecord);
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
- sService.mOomAdjuster.mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP_UID, app1UidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP2_UID, app2UidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP5_UID, app3UidRecord);
+ mService.mOomAdjuster.mActiveUids.put(MOCKAPP3_UID, clientUidRecord);
setServiceMap(s1, MOCKAPP_UID, cn1);
setServiceMap(s2, MOCKAPP2_UID, cn2);
@@ -2195,10 +2244,10 @@
app2UidRecord.setIdle(true);
app3UidRecord.setIdle(true);
clientUidRecord.setIdle(true);
- doReturn(ActivityManager.APP_START_MODE_DELAYED).when(sService)
+ doReturn(ActivityManager.APP_START_MODE_DELAYED).when(mService)
.getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
- doNothing().when(sService.mServices)
+ doNothing().when(mService.mServices)
.scheduleServiceTimeoutLocked(any(ProcessRecord.class));
updateOomAdj(client1, client2, app1, app2, app3);
@@ -2206,11 +2255,11 @@
assertEquals(PROCESS_STATE_SERVICE, app1.mState.getSetProcState());
assertEquals(PROCESS_STATE_SERVICE, client2.mState.getSetProcState());
} finally {
- doCallRealMethod().when(sService)
+ doCallRealMethod().when(mService)
.getAppStartModeLOSP(anyInt(), any(String.class), anyInt(),
anyInt(), anyBoolean(), anyBoolean(), anyBoolean());
- sService.mServices.mServiceMap.clear();
- sService.mOomAdjuster.mActiveUids.clear();
+ mService.mServices.mServiceMap.clear();
+ mService.mOomAdjuster.mActiveUids.clear();
}
}
@@ -2224,7 +2273,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2);
assertProcStates(app, PROCESS_STATE_TRANSIENT_BACKGROUND, PERCEPTIBLE_APP_ADJ,
@@ -2244,7 +2293,7 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
app2.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app2, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2268,7 +2317,7 @@
bindService(app2, app3, null, null, 0, mock(IBinder.class));
app3.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app3, app, null, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2313,7 +2362,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3, app4, app5);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2355,7 +2404,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app5, app4, app3, app2, app);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2397,7 +2446,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindService(app, app5, null, s, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app3, app4, app2, app, app5);
assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2437,7 +2486,7 @@
client3.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
bindService(app, client3, null, null, Context.BIND_INCLUDE_CAPABILITIES,
mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, client, client2, client3);
final int expected = PROCESS_CAPABILITY_ALL & ~PROCESS_CAPABILITY_BFSL;
@@ -2468,7 +2517,7 @@
MOCKAPP5_PROCESSNAME, MOCKAPP5_PACKAGENAME, false));
app5.mServices.setHasForegroundServices(true, 0, /* hasNoneType=*/true);
bindProvider(app, app5, cr, null, false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app, app2, app3, app4, app5);
assertProcStates(app, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
@@ -2512,8 +2561,8 @@
doCallRealMethod().when(s).getConnections();
s.startRequested = true;
s.lastActivity = now;
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.mNumServiceProcs = 3;
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mOomAdjuster.mNumServiceProcs = 3;
updateOomAdj(app3, app2, app);
assertEquals(SERVICE_B_ADJ, app3.mState.getSetAdj());
@@ -2530,15 +2579,15 @@
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
final int userOwner = 0;
final int userOther = 1;
- final int cachedAdj1 = sService.mConstants.USE_TIERED_CACHED_ADJ
+ final int cachedAdj1 = mService.mConstants.USE_TIERED_CACHED_ADJ
? CACHED_APP_MIN_ADJ + 10
: CACHED_APP_MIN_ADJ + ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
- final int cachedAdj2 = sService.mConstants.USE_TIERED_CACHED_ADJ
+ final int cachedAdj2 = mService.mConstants.USE_TIERED_CACHED_ADJ
? CACHED_APP_MIN_ADJ + 10
: cachedAdj1 + ProcessList.CACHED_APP_IMPORTANCE_LEVELS * 2;
- doReturn(userOwner).when(sService.mUserController).getCurrentUserId();
+ doReturn(userOwner).when(mService.mUserController).getCurrentUserId();
- final ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
+ final ArrayList<ProcessRecord> lru = mService.mProcessList.getLruProcessesLOSP();
lru.clear();
lru.add(app2);
lru.add(app);
@@ -2549,10 +2598,10 @@
MOCKAPP2_PACKAGENAME + "/.TestService");
final long now = SystemClock.uptimeMillis();
- sService.mConstants.KEEP_WARMING_SERVICES.clear();
+ mService.mConstants.KEEP_WARMING_SERVICES.clear();
final ServiceInfo si = mock(ServiceInfo.class);
si.applicationInfo = mock(ApplicationInfo.class);
- ServiceRecord s = spy(new ServiceRecord(sService, cn, cn, null, 0, null,
+ ServiceRecord s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
si, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
s.startRequested = true;
@@ -2564,16 +2613,16 @@
final ServiceInfo si2 = mock(ServiceInfo.class);
si2.applicationInfo = mock(ApplicationInfo.class);
si2.applicationInfo.uid = MOCKAPP2_UID_OTHER;
- ServiceRecord s2 = spy(new ServiceRecord(sService, cn2, cn2, null, 0, null,
+ ServiceRecord s2 = spy(new ServiceRecord(mService, cn2, cn2, null, 0, null,
si2, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s2).getConnections();
s2.startRequested = true;
- s2.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ s2.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
app2.mServices.startService(s2);
app2.mState.setHasShownUi(false);
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services");
@@ -2590,7 +2639,7 @@
app.mState.setSetProcState(PROCESS_STATE_NONEXISTENT);
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
- s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
@@ -2600,9 +2649,9 @@
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
app.mState.setHasShownUi(true);
- sService.mConstants.KEEP_WARMING_SERVICES.add(cn);
- sService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
- s = spy(new ServiceRecord(sService, cn, cn, null, 0, null,
+ mService.mConstants.KEEP_WARMING_SERVICES.add(cn);
+ mService.mConstants.KEEP_WARMING_SERVICES.add(cn2);
+ s = spy(new ServiceRecord(mService, cn, cn, null, 0, null,
si, false, null));
doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
s.startRequested = true;
@@ -2618,14 +2667,14 @@
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
app.mState.setHasShownUi(false);
- s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
+ s.lastActivity = now - mService.mConstants.MAX_SERVICE_INACTIVITY - 1;
updateOomAdj();
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
- doReturn(userOther).when(sService.mUserController).getCurrentUserId();
- sService.mOomAdjuster.handleUserSwitchedLocked();
+ doReturn(userOther).when(mService.mUserController).getCurrentUserId();
+ mService.mOomAdjuster.handleUserSwitchedLocked();
updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
@@ -2637,9 +2686,9 @@
public void testUpdateOomAdj_DoOne_AboveClient_SameProcess() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2672,8 +2721,8 @@
s = bindService(app3, app2, null, null, 0, mock(IBinder.class));
s.lastActivity = now;
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.mNumServiceProcs = 3;
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mOomAdjuster.mNumServiceProcs = 3;
updateOomAdj(app, app2, app3);
assertEquals(SERVICE_ADJ, app.mState.getSetAdj());
@@ -2688,9 +2737,9 @@
public void testUpdateOomAdj_DoOne_AboveClient_NotStarted() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
- doReturn(app).when(sService).getTopApp();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ doReturn(PROCESS_STATE_TOP).when(mService.mAtmInternal).getTopProcessState();
+ doReturn(app).when(mService).getTopApp();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
@@ -2718,7 +2767,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2738,7 +2787,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdjPending(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2760,7 +2809,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2781,7 +2830,7 @@
ServiceRecord s = makeServiceRecord(app);
s.startRequested = true;
s.lastActivity = SystemClock.uptimeMillis();
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdjPending(app);
assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND);
@@ -2809,7 +2858,7 @@
client.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
attributedClient.mServices.setHasForegroundServices(true, 0, true);
bindService(sandboxService, client, attributedClient, null, 0, mock(IBinder.class));
- sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj();
assertProcStates(client, PROCESS_STATE_PERSISTENT, PERSISTENT_PROC_ADJ,
SCHED_GROUP_DEFAULT);
@@ -2830,13 +2879,13 @@
// App1 binds to app2 and gets temp allowlisted.
bindService(app2, app, null, null, 0, mock(IBinder.class));
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertEquals(true, app.mOptRecord.shouldNotFreeze());
assertEquals(true, app2.mOptRecord.shouldNotFreeze());
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
assertEquals(false, app2.mOptRecord.shouldNotFreeze());
@@ -2856,8 +2905,8 @@
// App1 and app2 both bind to app3 and get temp allowlisted.
bindService(app3, app, null, null, 0, mock(IBinder.class));
bindService(app3, app2, null, null, 0, mock(IBinder.class));
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, true);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, true);
assertEquals(true, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
@@ -2866,7 +2915,7 @@
assertEquals(true, app3.mOptRecord.shouldNotFreeze());
// Remove app1 from allowlist.
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(true, app2.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -2874,7 +2923,7 @@
assertEquals(true, app3.mOptRecord.shouldNotFreeze());
// Now remove app2 from allowlist.
- sService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
+ mService.mOomAdjuster.setUidTempAllowlistStateLSP(MOCKAPP2_UID, false);
assertEquals(false, app.getUidRecord().isSetAllowListed());
assertEquals(false, app2.getUidRecord().isSetAllowListed());
assertEquals(false, app.mOptRecord.shouldNotFreeze());
@@ -2882,6 +2931,73 @@
assertEquals(false, app3.mOptRecord.shouldNotFreeze());
}
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUpdateOomAdj_DoAll_ClientlessService() {
+ ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+
+ setProcessesToLru(app);
+ ServiceRecord s = makeServiceRecord(app);
+ s.startRequested = true;
+ s.lastActivity = SystemClock.uptimeMillis();
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ updateOomAdj();
+ assertProcStates(app, PROCESS_STATE_SERVICE, SERVICE_ADJ, SCHED_GROUP_BACKGROUND,
+ "started-services");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app, PROCESS_STATE_SERVICE, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-started-services");
+ // Follow up should not have been called again.
+ verify(mService.mHandler).sendEmptyMessageAtTime(eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG),
+ followUpTimeCaptor.capture());
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testUpdateOomAdj_DoAll_Multiple_Provider_Retention() {
+ ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ app1.mProviders.setLastProviderTime(SystemClock.uptimeMillis());
+ app2.mProviders.setLastProviderTime(SystemClock.uptimeMillis() + 2000);
+ mService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ setProcessesToLru(app1, app2);
+ mService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+
+ assertProcStates(app1, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
+ SCHED_GROUP_BACKGROUND, "recent-provider");
+ assertProcStates(app2, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ,
+ SCHED_GROUP_BACKGROUND, "recent-provider");
+
+ if (!Flags.followUpOomadjUpdates()) return;
+
+ final ArgumentCaptor<Long> followUpTimeCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+
+ assertProcStates(app1, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-empty");
+
+ verify(mService.mHandler, atLeastOnce()).sendEmptyMessageAtTime(
+ eq(FOLLOW_UP_OOMADJUSTER_UPDATE_MSG), followUpTimeCaptor.capture());
+ mInjector.jumpUptimeAheadTo(followUpTimeCaptor.getValue());
+ mService.mOomAdjuster.updateOomAdjFollowUpTargetsLocked();
+ assertProcStates(app2, PROCESS_STATE_CACHED_EMPTY, sFirstCachedAdj, SCHED_GROUP_BACKGROUND,
+ "cch-empty");
+ }
+
private ProcessRecord makeDefaultProcessRecord(int pid, int uid, String processName,
String packageName, boolean hasShownUi) {
return new ProcessRecordBuilder(pid, uid, processName, packageName).setHasShownUi(
@@ -2904,7 +3020,7 @@
}
private void setServiceMap(ServiceRecord s, int uid, ComponentName cn) {
- ActiveServices.ServiceMap serviceMap = sService.mServices.mServiceMap.get(
+ ActiveServices.ServiceMap serviceMap = mService.mServices.mServiceMap.get(
UserHandle.getUserId(uid));
if (serviceMap == null) {
serviceMap = mock(ActiveServices.ServiceMap.class);
@@ -2916,7 +3032,7 @@
new ArrayMap<>());
setFieldValue(ActiveServices.ServiceMap.class, serviceMap, "mDelayedStartList",
new ArrayList<>());
- sService.mServices.mServiceMap.put(UserHandle.getUserId(uid), serviceMap);
+ mService.mServices.mServiceMap.put(UserHandle.getUserId(uid), serviceMap);
}
serviceMap.mServicesByInstanceName.put(cn, s);
}
@@ -2957,6 +3073,7 @@
return record;
}
+ @SuppressWarnings("GuardedBy")
private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
int expectedSchedGroup) {
final ProcessStateRecord state = app.mState;
@@ -2974,6 +3091,7 @@
}
}
+ @SuppressWarnings("GuardedBy")
private void assertProcStates(ProcessRecord app, boolean expectedCached,
int expectedProcState, int expectedAdj, String expectedAdjType) {
final ProcessStateRecord state = app.mState;
@@ -2992,7 +3110,26 @@
}
}
- private static class ProcessRecordBuilder {
+ @SuppressWarnings("GuardedBy")
+ private void assertProcStates(ProcessRecord app, int expectedProcState, int expectedAdj,
+ int expectedSchedGroup, String expectedAdjType) {
+ final ProcessStateRecord state = app.mState;
+ assertEquals(expectedAdjType, state.getAdjType());
+ assertEquals(expectedProcState, state.getSetProcState());
+ assertEquals(expectedAdj, state.getSetAdj());
+ assertEquals(expectedSchedGroup, state.getSetSchedGroup());
+
+ // Below BFGS should never have BFSL.
+ if (expectedProcState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
+ assertNoBfsl(app);
+ }
+ // Above FGS should always have BFSL.
+ if (expectedProcState < PROCESS_STATE_FOREGROUND_SERVICE) {
+ assertBfsl(app);
+ }
+ }
+
+ private class ProcessRecordBuilder {
@SuppressWarnings("UnusedVariable")
int mPid;
int mUid;
@@ -3069,17 +3206,17 @@
ai.packageName = mPackageName;
ai.longVersionCode = mVersionCode;
ai.targetSdkVersion = mTargetSdkVersion;
- doCallRealMethod().when(sService).getPackageManagerInternal();
- doReturn(null).when(sPackageManagerInternal).getApplicationInfo(
+ doCallRealMethod().when(mService).getPackageManagerInternal();
+ doReturn(null).when(mPackageManagerInternal).getApplicationInfo(
eq(mSdkSandboxClientAppPackage), anyLong(), anyInt(), anyInt());
- ProcessRecord app = new ProcessRecord(sService, ai, mProcessName, mUid,
+ ProcessRecord app = new ProcessRecord(mService, ai, mProcessName, mUid,
mSdkSandboxClientAppPackage, -1, null);
final ProcessStateRecord state = app.mState;
final ProcessServiceRecord services = app.mServices;
final ProcessReceiverRecord receivers = app.mReceivers;
final ProcessProfileRecord profile = app.mProfile;
final ProcessProviderRecord providers = app.mProviders;
- app.makeActive(mock(IApplicationThread.class), sService.mProcessStats);
+ app.makeActive(mock(IApplicationThread.class), mService.mProcessStats);
app.setLastActivityTime(mLastActivityTime);
app.setKilledByAm(mKilledByAm);
app.setIsolatedEntryPoint(mIsolatedEntryPoint);
@@ -3124,14 +3261,35 @@
}
providers.setLastProviderTime(mLastProviderTime);
- UidRecord uidRec = sService.mOomAdjuster.mActiveUids.get(mUid);
+ UidRecord uidRec = mService.mOomAdjuster.mActiveUids.get(mUid);
if (uidRec == null) {
- uidRec = new UidRecord(mUid, sService);
- sService.mOomAdjuster.mActiveUids.put(mUid, uidRec);
+ uidRec = new UidRecord(mUid, mService);
+ mService.mOomAdjuster.mActiveUids.put(mUid, uidRec);
}
uidRec.addProcess(app);
app.setUidRecord(uidRec);
return app;
}
}
+
+ static class OomAdjusterInjector extends OomAdjuster.Injector {
+ // Jump ahead in time by this offset amount.
+ long mTimeOffsetMillis = 0;
+
+ void jumpUptimeAheadTo(long uptimeMillis) {
+ final long jumpMs = uptimeMillis - getUptimeMillis();
+ if (jumpMs <= 0) return;
+ mTimeOffsetMillis += jumpMs;
+ }
+
+ @Override
+ long getUptimeMillis() {
+ return SystemClock.uptimeMillis() + mTimeOffsetMillis;
+ }
+
+ @Override
+ long getElapsedRealtimeMillis() {
+ return SystemClock.elapsedRealtime() + mTimeOffsetMillis;
+ }
+ }
}
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index 4460c6a..ce2bb95 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.SensorManager;
@@ -41,7 +42,6 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.VibrationAttributes;
import android.os.Vibrator;
import android.os.test.TestLooper;
@@ -82,8 +82,12 @@
@Mock private StatusBarManagerInternal mStatusBarManagerInternal;
@Mock private WakeLockLog mWakeLockLog;
+ @Mock private IBatteryStats mBatteryStats;
+
@Mock private PowerManagerFlags mPowerManagerFlags;
+ @Mock private AppOpsManager mAppOpsManager;
+
private PowerManagerService mService;
private Context mContextSpy;
private Resources mResourcesSpy;
@@ -230,7 +234,7 @@
public void testOnWakeLockListener_RemoteException_NoRethrow() {
when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
createNotifier();
-
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
@Override public void onStateChanged(boolean enabled) throws RemoteException {
throw new RemoteException("Just testing");
@@ -245,6 +249,7 @@
verifyZeroInteractions(mWakeLockLog);
mTestLooper.dispatchAll();
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
+
mNotifier.onWakeLockAcquired(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
exceptingCallback);
@@ -277,6 +282,115 @@
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
}
+
+ @Test
+ public void testOnWakeLockListener_FullWakeLock_ProcessesOnHandler() throws RemoteException {
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
+ createNotifier();
+
+ IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
+ @Override public void onStateChanged(boolean enabled) throws RemoteException {
+ throw new RemoteException("Just testing");
+ }
+ };
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ final int uid = 1234;
+ final int pid = 5678;
+
+ // Release the wakelock
+ mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ // No interaction because we expect that to happen in async
+ verifyZeroInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Progressing the looper, and validating all the interactions
+ mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, 1);
+ verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL);
+ verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", null);
+
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Acquire the wakelock
+ mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ // No interaction because we expect that to happen in async
+ verifyNoMoreInteractions(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Progressing the looper, and validating all the interactions
+ mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, 1);
+ verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL, false);
+ verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", false, null, null);
+
+ // Test with improveWakelockLatency flag false, hence the wakelock log will run on the same
+ // thread
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(false);
+
+ mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1);
+
+ mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
+ }
+
+ @Test
+ public void testOnWakeLockListener_FullWakeLock_ProcessesInSync() throws RemoteException {
+ createNotifier();
+
+ IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
+ @Override public void onStateChanged(boolean enabled) throws RemoteException {
+ throw new RemoteException("Just testing");
+ }
+ };
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ final int uid = 1234;
+ final int pid = 5678;
+
+ // Release the wakelock
+ mNotifier.onWakeLockReleased(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
+ verify(mBatteryStats).noteStopWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL);
+ verify(mAppOpsManager).finishOp(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", null);
+
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+
+ // Acquire the wakelock
+ mNotifier.onWakeLockAcquired(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, /* workSource= */ null, /* historyTag= */ null,
+ exceptingCallback);
+
+ mTestLooper.dispatchAll();
+ verify(mWakeLockLog).onWakeLockAcquired("wakelockTag", uid,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, -1);
+ verify(mBatteryStats).noteStartWakelock(uid, pid, "wakelockTag", /* historyTag= */ null,
+ BatteryStats.WAKE_TYPE_FULL, false);
+ verify(mAppOpsManager).startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, uid,
+ "my.package.name", false, null, null);
+ }
+
private final PowerManagerService.Injector mInjector = new PowerManagerService.Injector() {
@Override
Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
@@ -365,13 +479,17 @@
public WakeLockLog getWakeLockLog(Context context) {
return mWakeLockLog;
}
+
+ @Override
+ public AppOpsManager getAppOpsManager(Context context) {
+ return mAppOpsManager;
+ }
};
mNotifier = new Notifier(
mTestLooper.getLooper(),
mContextSpy,
- IBatteryStats.Stub.asInterface(ServiceManager.getService(
- BatteryStats.SERVICE_NAME)),
+ mBatteryStats,
mInjector.createSuspendBlocker(mService, "testBlocker"),
null,
null,
diff --git a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
index 8cbed2c..31bf5f0 100644
--- a/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/OomAdjusterTests.java
@@ -61,20 +61,6 @@
private static final long USAGE_STATS_INTERACTION = 10 * 60 * 1000L;
private static final long SERVICE_USAGE_INTERACTION = 60 * 1000;
- static class MyOomAdjuster extends OomAdjuster {
-
- MyOomAdjuster(ActivityManagerService service, ProcessList processList,
- ActiveUids activeUids) {
- super(service, processList, activeUids);
- }
-
- @Override
- protected boolean isChangeEnabled(int changeId, ApplicationInfo app,
- boolean defaultValue) {
- return true;
- }
- }
-
@BeforeClass
public static void setUpOnce() {
sContext = getInstrumentation().getTargetContext();
@@ -99,7 +85,15 @@
final AppProfiler profiler = mock(AppProfiler.class);
setFieldValue(AppProfiler.class, profiler, "mProfilerLock", new Object());
setFieldValue(ActivityManagerService.class, sService, "mAppProfiler", profiler);
- sService.mOomAdjuster = new MyOomAdjuster(sService, sService.mProcessList, null);
+ final OomAdjuster.Injector injector = new OomAdjuster.Injector(){
+ @Override
+ boolean isChangeEnabled(int changeId, ApplicationInfo app,
+ boolean defaultValue) {
+ return true;
+ }
+ };
+ sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList, null,
+ injector);
LocalServices.addService(UsageStatsManagerInternal.class,
mock(UsageStatsManagerInternal.class));
sService.mUsageStatsService = LocalServices.getService(UsageStatsManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 3cab75b..3d68849 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,11 +18,13 @@
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK;
+import static android.app.ActivityManager.MAX_PROCESS_STATE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK;
import static android.app.ActivityManager.PROCESS_CAPABILITY_USER_RESTRICTED_NETWORK;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
@@ -165,9 +167,11 @@
import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.SimpleClock;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -2158,7 +2162,8 @@
@Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
- public void testBackgroundChainOnProcStateChange() throws Exception {
+ @RequiresFlagsDisabled(Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN)
+ public void testBackgroundChainOnProcStateChangeSameDelay() throws Exception {
// initialization calls setFirewallChainEnabled, so we want to reset the invocations.
clearInvocations(mNetworkManager);
@@ -2186,6 +2191,59 @@
}
@Test
+ @RequiresFlagsEnabled({
+ Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE,
+ Flags.FLAG_USE_DIFFERENT_DELAYS_FOR_BACKGROUND_CHAIN
+ })
+ public void testBackgroundChainOnProcStateChangeDifferentDelays() throws Exception {
+ // The app will be blocked when there is no prior proc-state.
+ assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+
+ // Tweak delays to avoid waiting too long in tests.
+ mService.mBackgroundRestrictionShortDelayMs = 50;
+ mService.mBackgroundRestrictionLongDelayMs = 1000;
+
+ int procStateSeq = 231; // Any arbitrary starting sequence.
+ for (int ps = BACKGROUND_THRESHOLD_STATE; ps <= MAX_PROCESS_STATE; ps++) {
+ clearInvocations(mNetworkManager);
+
+ // Make sure app is in correct process-state to access network.
+ callAndWaitOnUidStateChanged(UID_A, BACKGROUND_THRESHOLD_STATE - 1, procStateSeq++);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A,
+ FIREWALL_RULE_ALLOW);
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+
+ // Now put the app into the background and test that it eventually loses network.
+ callAndWaitOnUidStateChanged(UID_A, ps, procStateSeq++);
+
+ final long uidStateChangeTime = SystemClock.uptimeMillis();
+ if (ps <= PROCESS_STATE_LAST_ACTIVITY) {
+ // Verify that the app is blocked after long delay but not after short delay.
+ waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1);
+ verify(mNetworkManager, never()).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND,
+ UID_A, FIREWALL_RULE_DEFAULT);
+ assertFalse(mService.isUidNetworkingBlocked(UID_A, false));
+
+ final long timeUntilLongDelay = uidStateChangeTime
+ + mService.mBackgroundRestrictionLongDelayMs - SystemClock.uptimeMillis();
+ assertTrue("No time left to verify long delay in background transition",
+ timeUntilLongDelay >= 0);
+
+ waitForDelayedMessageOnHandler(timeUntilLongDelay + 1);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A,
+ FIREWALL_RULE_DEFAULT);
+ assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+ } else {
+ // Verify that the app is blocked after short delay.
+ waitForDelayedMessageOnHandler(mService.mBackgroundRestrictionShortDelayMs + 1);
+ verify(mNetworkManager).setFirewallUidRule(FIREWALL_CHAIN_BACKGROUND, UID_A,
+ FIREWALL_RULE_DEFAULT);
+ assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
+ }
+ }
+ }
+
+ @Test
@RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
public void testBackgroundChainOnAllowlistChange() throws Exception {
// initialization calls setFirewallChainEnabled, so we want to reset the invocations.
@@ -2881,6 +2939,11 @@
}
}
+ /**
+ * This posts a blocking message to the service handler with the given delayMs and waits for it
+ * to complete. This ensures that all messages posted before the given delayMs will also
+ * have been executed before this method returns and can be verified in subsequent code.
+ */
private void waitForDelayedMessageOnHandler(long delayMs) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
mService.getHandlerForTesting().postDelayed(latch::countDown, delayMs);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 0f28528..e019a41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -1235,12 +1235,18 @@
assertEquals(STOPPING, activity2.getState());
assertThat(mSupervisor.mStoppingActivities).contains(activity2);
+ registerTestTransitionPlayer();
+ final Transition transition = display.mTransitionController
+ .requestCloseTransitionIfNeeded(rootTask1);
+ transition.collectClose(rootTask1);
// The display becomes empty. Since there is no next activity to be idle, the activity
// should be destroyed immediately with updating configuration to restore original state.
final ActivityRecord activity1 = finishTopActivity(rootTask1);
assertEquals(DESTROYING, activity1.getState());
verify(mRootWindowContainer).ensureVisibilityAndConfig(eq(null) /* starting */,
eq(display), anyBoolean());
+ assertTrue("Transition must be ready if there is no next running activity",
+ transition.allReady());
}
private ActivityRecord finishTopActivity(Task task) {
diff --git a/tests/Input/assets/testPointerScale.png b/tests/Input/assets/testPointerScale.png
new file mode 100644
index 0000000..54d37c2
--- /dev/null
+++ b/tests/Input/assets/testPointerScale.png
Binary files differ
diff --git a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
index dac4253..d196b85 100644
--- a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
+++ b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
@@ -93,7 +93,29 @@
PointerIcon.getLoadedSystemIcon(
ContextThemeWrapper(context, theme),
PointerIcon.TYPE_ARROW,
- /* useLargeIcons= */ false)
+ /* useLargeIcons= */ false,
+ /* pointerScale= */ 1f)
+
+ pointerIcon.getBitmap().assertAgainstGolden(
+ screenshotRule,
+ testName.methodName,
+ exactScreenshotMatcher
+ )
+ }
+
+ @Test
+ fun testPointerScale() {
+ assumeTrue(enableVectorCursors())
+ assumeTrue(enableVectorCursorA11ySettings())
+
+ val pointerScale = 2f
+
+ val pointerIcon =
+ PointerIcon.getLoadedSystemIcon(
+ context,
+ PointerIcon.TYPE_ARROW,
+ /* useLargeIcons= */ false,
+ pointerScale)
pointerIcon.getBitmap().assertAgainstGolden(
screenshotRule,